@digo-labs/服务
Digo平台的浏览器客户端:auth,设备密钥,后端API,数据库表格,文件存储,websocket通道,AI生成和AI任务.
如何是观此相. 这个带包的向导船,因此与您所安装的版本相匹配;站点描述了最新的发布. 类型 node_modules/@digo-labs/services/dist/*.d.ts 如果他们不同意,是准确的,是赢的。 更深的页面 : https://design.digo-labs.com/docs/guide/package-services (中文(简体) )。 。 。 .
设置
不要手动关闭此软件包 . defineApp 从 @digo-labs/app 注册应用程序名称、电话 AuthHelper.init (与 auth和 ApiHelper.init (与 backend: true,然后运行您的 services 工厂,在工厂里建造以下的类(...databases, (中文(简体) ), new Storage(), (中文(简体) ), new Websockets<Channels>(), (中文(简体) ), new Ai()) (中文(简体) ).
认证 : useAuth, (中文(简体) ), useGoogleSignIn, (中文(简体) ), AuthHelper
import { useAuth } from '@digo-labs/services';
const { user, session, device, instance, isReadOnly, tier, globalTier, isLoading, isOffline, isAuthenticated, signIn, signOut } = useAuth();
await signIn.social({ provider: 'google', callbackURL: window.location.href });
tier 实值 'public' | 'user' | 'org' | 'admin' 在选定的实例中: 注册设备的分级胜出; 否则 org 是一个已验证的 @productionclub.net 电子邮件,以及 admin 管理者的角色或管理者. instance 是所选实例的弹出和 globalTier 忽略实例角色:门实例管理、预算限制、文本、代理和其中的DMX. isReadOnly 当实例被存档时是真实的( 一个归档撤销了实例的设备密钥, 因此设备获得 401) (中文(简体) ). isAuthenticated 对用户或设备来说是真实的. AuthHelper.auth 是原始的更好的 Auth 客户端(包括admin 插件).
对于谷歌的登录按钮, useGoogleSignIn({ callbackPath }) (默认) '/'返回时 { signIn, isSigningIn, error }数字 : signIn() 重定向到谷歌并返回 callbackPath 并决心 Result<void> tu; isSigningIn 在浏览器离开或请求失败之前是真实的; error 保持失败.
import { useGoogleSignIn } from '@digo-labs/services';
const { signIn, isSigningIn } = useGoogleSignIn({ callbackPath: from });
async function handleSignIn() {
const [, error] = await signIn();
if (error) {
console.error(error);
setMessage('Sign in failed. Please try again.');
}
}
<button onClick={handleSignIn} disabled={isSigningIn}>Continue with Google</button>
设备密钥 : Devices, (中文(简体) ), useDevice, (中文(简体) ), DeviceHelper
一个设备密钥让一个亭子在层上行动,没有人签字. 它属于它创建于,生活于 localStorage 并发送到每个 API 呼叫中; 装入设备将它的浏览器切换到它的密钥实例中 .
const devices = new Devices();
await devices.enrol({ name: 'Booth 1', tier: 'org', expiresInDays: 30 }); // create and store the key here, then sign this browser out
await devices.create({ name: 'Booth 2' }); // { device, key }, key not stored
await devices.list(); // DeviceRecord[]
await devices.revoke(id); // boolean
await devices.regenerate(id); // { device, key }: old key revoked, new one revealable
devices.forget(); // drop this device's key
await devices.create({ name: 'Booth 3', isRevealable: true }); // keep an encrypted copy
await devices.reveal(id); // the key again (admin, while revealable)
await devices.lock(id); // boolean: drop the copy for good, key keeps working
await devices.lockAll(); // number of keys locked in this instance
tier 实值 'user' | 'org' (默认) 'org', (中文(简体) ), expiresInDays 最多365起(违约30起)或 null 为永远. DeviceRecord.isRevealable 说钥匙是否还有副本. useDevice() 返回时 { device, isLoading, isOffline }页:1 401 丢弃存储的密钥, 而其它任何失败( 网络出错、 超时、 其它) 4xx页:1 5xx(组数) isOffline,保留 device 作为记录,最后确认的后端(插入 localStorage自行检讨; DeviceHelper.setKey(key) 编号 : clearKey() 管理存储的密钥.
数据库 : Database<T>
每表一例. 类型实例来自 defineDatabases (单位:千美元)@digo-labs/app/database; 直接为共享表格构建一个: new Database<StyleRecord>('styles') (第二个参数:主键,默认值) 'id') (中文(简体) ).
await services.items.getAll(50, 0); // T[] (limit?, offset?), in primary-key order
await services.items.get(id); // T | null
await services.items.getBy('name', 'Hello'); // T[] (column, value, limit?, offset?)
await services.items.readAll(); // T[] every row, paged by primary key
await services.items.readAllBy('name', 'Hello'); // T[] every matching row
await services.items.create({ name: 'Hello' }); // T
await services.items.update(id, { name: 'Hi' }); // boolean
await services.items.update(id, { status: 'printing' }, { status: 'queued' }); // only if it still matches (needs read too)
await services.items.delete(id); // boolean
读取整个表格的使用 readAll编号 :readAllBy没有循环 offset:它们在上一个主键读取后再行行,所以每个从起到终所存在的行都会被精确地读取一次,即使其他行被更改,添加或去除(单列主键只有;其他表格得到400个).
访问量为每张表格,在 src/db.ts 并同步 by digo-db push;没有规则的表格被拒绝。 客户端可能不会发送 id (给它一个数据库默认) 或表格的 owner 栏(后端从会话中填充).
实例 : Instances, (中文(简体) ), useInstance, (中文(简体) ), InstanceHelper
一个应用软件的孤立装置(schema,文件,已签名的频道,设备密钥,AI预算各一;开放频道只获得其名下的实例). main 总是存在的; 请求将实例带入 X-Digo-Instance: 页面主机( q)jon.<app>.digo-labs.com 实值 jon),否则浏览器的选择,否则 main。一个未知的存储选择被丢弃,页面重新装入 main,是否签名.
const instances = new Instances();
await instances.list(); // main, then all for a global admin or the ones you administer
await instances.current(); // { instance, tier, isReadOnly }
instances.select('jon'); // store for this browser and reload
instances.getSelected(); // 'jon'
await instances.create({ slug: 'jon', name: 'Jon' }); // global admins only, like the calls below
await instances.rename('main', 'Las Vegas');
await instances.archive('jon'); // read-only, device keys revoked
await instances.reopen('jon');
await instances.setAdmins('jon', ['[email protected]']); // replaces the list; admins of that instance only, never main
await instances.getAdmins('jon');
useInstance({ userId }) 返回时 { instance, access, isLoading } (单位:千美元)access 仅在外部获取 main,在网络错误上重新测试,并丢弃一个未知存储实例; useAuth() 已经用过了.
存储 : Storage
应用程序的 S3 桶中的文件通过预签名链接 . new Storage() 用途 <app-name>-digo-labs-storage;通过共享桶的名称(new Storage('common-styles-digo-labs-storage')) (中文(简体) ).
const { path, url } = await storage.uploadFile(`sketches/${id}.png`, file); // File | Blob | ArrayBuffer, contentType?
await storage.uploadImage(path, { base64, mediaType: 'image/png' });
await storage.uploadFromUrl(path, remoteUrl, 'image/png');
storage.getUrl(path); // sync link through the files route
await storage.getSignedUrl(path, { expiresIn: 300 }); // short-lived link for private prefixes
await storage.download(path); // Blob
await storage.list('sketches/', { limit: 100 }); // StorageObject[]
await storage.delete([path]); // deleted paths
storage.getPathFromUrl(url); // string | null
在表格中存储路径,而不是链接 。 前缀规则来自 defineStorage 内 src/db.ts。路径相对选定的实例: jon 他们住在地下 _instances/jon/,哪个 getUrl, (中文(简体) ), getPathFromUrl 财务报告和审定财务报表 list 为您添加并删除.
网络锁定 : Websockets<TMap>
A. 在websocket中枢上打入的酒吧/分站; TMap 将频道名称映射到有效载荷。 它在构造器中连接,并自己重新连接.
interface Channels { cursor: { x: number; y: number; }; }
const ws = new Websockets<Channels>({ auth: true });
ws.subscribe('cursor', data => move(data.x, data.y));
ws.send('cursor', { x: 1, y: 2 }); // to current subscribers
ws.setState('cursor', { x: 1, y: 2 }); // kept on the hub, replayed to new subscribers
ws.unsubscribe('cursor');
ws.onReady(() => refresh()); // also onOpen, onClose, onError, offReady, isLive, close
选项 : auth, (中文(简体) ), url (默认) wss://ws.digo-labs.com, (中文(简体) ), app, (中文(简体) ), id, (中文(简体) ), reconnect, (中文(简体) ), reconnectInterval, (中文(简体) ), maxReconnectInterval, (中文(简体) ), getToken。 。 。 .
- 打开 (默认):频道外出作为
<app>:<channel>(单位:千美元)<app>__<instance>:<channel>外部main),除非含有::或从_。命名大会;任何人都可以读取. - 签署于 (单位:千美元)
auth: true: 显示后端符号(会话或设备密钥); 名称按写并对照应用程序检查defineChannels规则.
大赦国际: Ai
const ai = new Ai();
const stream = ai.text.generate({ messages: [{ role: 'user', content: 'Hi' }], systemPrompt, maxTokens: 400 });
for await (const { text } of stream) append(text);
const { text, stopReason, isBlocked } = await stream.collect();
const image = await ai.image.generate({ prompt, aspectRatio: '16:9' }, { persist: 'generations/a.jpg' });
await ai.image.edit({ prompt, image: url, strength: 0.6 });
await ai.image.upscale({ image: url, factor: 2 });
await ai.image.removeBackground({ image: url });
await ai.video.generate({ prompt, aspectRatio: '9:16', durationSeconds: 5 });
await ai.audio.speech({ text, voice: 'af_heart' });
await ai.audio.music({ prompt, durationSeconds: 30 });
await ai.audio.transcribe({ audio: url, language: 'en' });
中途丢出失败的文本流 TextStreamError 带有 reason (单位:千美元)busy, (中文(简体) ), model_unavailable, (中文(简体) ), provider_down, (中文(简体) ), invalid_request 或者说 unknown) (中文(简体) ). 文字运行于贝德罗克;媒体运行于fal. 媒体选项是 { persist?, signal?, onProgress? } (单位:千美元)transcribe 财务报告和审定财务报表 text.generate 带 { signal } 页:1 结果为: { url, contentType?, width?, height?, seed?, durationSeconds?, model? }; 无 persist, (中文(简体) ), url 是提供者的临时链接,文件被复制到您的桶中 url 实值 storage.getUrl(persist)。原始供应商: ai.bedrock.converseStream(body, signal?), (中文(简体) ), ai.fal (单位:千美元)subscribe, (中文(简体) ), run, (中文(简体) ), stream, (中文(简体) ), queue,(......)和 ai.replicate (单位:千美元) replicate SDK),也导出为 Bedrock, (中文(简体) ), Fal, (中文(简体) ), Replicate。 。 。 .
AI 任务 : ai.jobs
后端运行的图像管道:输入检查,任务,输出保存到您的桶上,输出检查. 重新装入毫无损失.
const job = await services.ai.jobs.create({
key: `guest-${guestId}`, // idempotent per app instance
inputs: { sketch: `sketches/${guestId}.png` },
checks: [{ type: 'rekognition', input: 'sketch' }],
tasks: [{
key: 'traditional',
endpoint: 'fal:openai/gpt-image-2.5/flare/edit', // AI_JOB_ENDPOINTS in @digo-labs/common
input: { prompt, image_urls: [{ $input: 'sketch' }] },
output: { path: `designs/${guestId}/traditional.png` }, // under a write: 'server' prefix
}],
outputChecks: [{ type: 'rekognition' }],
});
const stop = services.ai.jobs.watch(job.id, current => setTasks(current.tasks));
还有 add(id, tasks), (中文(简体) ), check(id, taskKey, checks), (中文(简体) ), cancel(id), (中文(简体) ), get(id),以及 list(filters): 实例的工作是一页时间, 最古老的第一, 形状 get 返回; 过滤器 from 编号 : to (关于创作时间的ISO 8601, to (不包括), statuses, (中文(简体) ), limit (默认为100,最多为200),页面的 next,以 cursor 直到它变成这样 null。 。 。 . onReview 实值 'reject' (违约)或 'continue'。 。 。 . create 采取不 tasks 工作目前只检查其投入; add 然后工作的时候 checking,它的任务等待检查。 检查是 { type: 'rekognition', input?, reject?, review?, minConfidence?, timeoutMs? } 或者说 { type: 'bedrock', prompt, input?, guardrail?, model?, provider?, timeoutMs? }时 provider 实值 'bedrock' (违约)或 'anthropic' (无) guardrail 和(或) timeoutMs 3至25 s(默认情况下为25 s). watch 等待每个修改的后端( n)get(id, { since, signal }) 并停止一切. endpoint: 'fake:echo' 建造时没有损失 一个任务 fallbacks (最多2个) { endpoint, input? }(a) 在其提供商失败时接管 fallbackAfter (ms) 当电流缓慢时,也开始下一个; servedBy 命名保存图像的终点。 任何检查最多需要两个 fallbacks (或一个) fallback克劳德按顺序审查, 只有在前一个不能运行或时间用完的时候.
大赦国际的预算: ai.budgets
每个实例对工作的限制, 保留在后端. null 谓无量相.
const { budget, usage } = await services.ai.budgets.get();
await services.ai.budgets.update({ maxInFlight: null, dailyUsd: 200 }); // only the fields sent change
budget 实值 { maxTasksPerJob, maxInFlight, hourlyUsd, dailyUsd, isPaused } (违约30、8、10、50, false(三); usage 实值 { hourlyUsd, dailyUsd, inFlight },估计在最后一小时和一天的开支, 以及现在供应商的要求。 两种调用都根据呼叫者自己的应用程序和实例行事;改变限制需要一个全局管理员,而一个实例管理员只能暂停和恢复(isPaused) (中文(简体) ). 工作请求超过答案的上限 429。 。 。 .
低级和中央领导才能
ApiHelper.client是每个后端路由的被打入的Hono客户端;ApiHelper.unwrap<T>(promise)返回 JSON 或丢出一个Error与后端的信息.new Dmx().send(channel, value)设置 DMX 频道(仅限管理员).Realtime是空占位符; 使用Websockets。 。 。 .- 这个
digo-db二进制( e)npm run db:push应用程序中 :push创建计划, 运行drizzle-kit push,同步access, (中文(简体) ),storage财务报告和审定财务报表channels出口额src/db.ts并推进应用程序的每一个实例计划drop, (中文(简体) ),verify, (中文(简体) ),refresh, (中文(简体) ),schema-name需求DATABASE_URL_MONOREPO(和ADMIN_SECRET在环境, 即应用模板的scripts/with-monorepo-secrets.sh从 AWS 机密管理器中读取 :npm run db:push运行push通过它; 运行其他子命令 通过它),和drizzle-kit已安装.
抓到他们了
- 内建服务
services工厂.Storage财务报告和审定财务报表Websockets需要应用程序名称defineApp登记和扔出没有它;new Ai()构建一个Storage,所以它投掷也. useAuth需求auth内defineApp,或AuthHelper.auth掷出. 每页一个认证项目 .backendURL没有到达荒地或复制:他们的代理人总是使用https://api.digo-labs.com。 。 。 .- 分级后端执行 : 文本, fal/ 复制, 全部
ai.jobs电话和ai.budgets.get需求org· ;ai.budgets.update和设备创建/列表/撤销需要admin, (中文(简体) ),instances.list登录( e)instances.current实例管理是全球性的管理。 一个实例是admin仅根据该实例本身的数据、文件、频道、设备和工作;文本、fal/复制和DMX检查其全球层级。 存档实例解答写法423。 。 。 .401签字后,403当阶梯太低的时候. - 共享桌名取胜 . 后端决定
common表格(例如:styles)在应用程序之前,所以一个同名的应用程序表是无法到达的. getUrl仅在 a 下装入read: 'public'前缀 (次数)404; 使用情况getSignedUrl。 。 。 .getPublicUrl构建一个不装入的原始S3地址:桶是私有的.- 固定的 AI 值抛出其他 : 图像
aspectRatio1:1, (中文(简体) ),16:9, (中文(简体) ),9:16, (中文(简体) ),4:3, (中文(简体) ),3:4; 视频16:9, (中文(简体) ),9:16, (中文(简体) ),1:1(一) 持续时间中断至5或10秒;voice必须是克克洛的声音(af_heart, (中文(简体) ),am_adam(中文(简体) ). - 网页
send编号 :setState已断开未排队。 重读状态onReady。 。 。 .