@abloatai/ablo 0.11.0 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/README.md +72 -25
- package/dist/Model.d.ts +39 -0
- package/dist/Model.js +68 -0
- package/dist/auth/credentialPolicy.d.ts +145 -0
- package/dist/auth/credentialPolicy.js +130 -0
- package/dist/cli.cjs +154 -25
- package/dist/client/Ablo.d.ts +39 -88
- package/dist/client/Ablo.js +54 -99
- package/dist/client/ApiClient.d.ts +10 -1
- package/dist/client/ApiClient.js +23 -12
- package/dist/client/auth.d.ts +21 -9
- package/dist/client/auth.js +42 -6
- package/dist/client/createModelProxy.d.ts +74 -10
- package/dist/client/createModelProxy.js +85 -4
- package/dist/client/httpClient.d.ts +17 -3
- package/dist/client/httpClient.js +1 -0
- package/dist/client/identity.js +134 -122
- package/dist/client/index.d.ts +1 -1
- package/dist/client/sessionMint.d.ts +15 -0
- package/dist/client/sessionMint.js +86 -0
- package/dist/errorCodes.d.ts +2 -0
- package/dist/errorCodes.js +3 -1
- package/dist/errors.d.ts +3 -2
- package/dist/errors.js +3 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -7
- package/dist/mutators/RecordingTransaction.js +14 -42
- package/dist/react/AbloProvider.d.ts +1 -6
- package/dist/react/AbloProvider.js +1 -5
- package/dist/react/context.d.ts +1 -31
- package/dist/react/context.js +2 -2
- package/dist/react/index.d.ts +0 -6
- package/dist/react/index.js +0 -7
- package/dist/react/useSyncStatus.d.ts +1 -1
- package/dist/realtime/index.d.ts +1 -1
- package/dist/schema/generate.js +1 -2
- package/dist/schema/schema.d.ts +16 -5
- package/dist/schema/schema.js +26 -0
- package/dist/surface.d.ts +29 -0
- package/dist/surface.js +60 -0
- package/dist/sync/ConnectionManager.d.ts +16 -5
- package/dist/sync/ConnectionManager.js +42 -7
- package/dist/transactions/TransactionQueue.js +22 -10
- package/dist/types/global.d.ts +11 -3
- package/dist/types/global.js +8 -3
- package/dist/types/streams.d.ts +0 -22
- package/dist/utils/mobx-setup.js +1 -0
- package/docs/api-keys.md +49 -0
- package/docs/api.md +6 -5
- package/docs/client-behavior.md +7 -3
- package/docs/coordination.md +88 -24
- package/docs/data-sources.md +29 -9
- package/docs/examples/existing-python-backend.md +9 -5
- package/docs/examples/scoped-agent.md +1 -1
- package/docs/guarantees.md +4 -3
- package/docs/identity.md +89 -82
- package/docs/integration-guide.md +19 -10
- package/docs/migration.md +49 -2
- package/docs/quickstart.md +65 -33
- package/docs/react.md +49 -3
- package/docs/schema-contract.md +23 -5
- package/llms-full.txt +43 -24
- package/llms.txt +17 -15
- package/package.json +1 -1
- package/dist/api/index.d.ts +0 -10
- package/dist/api/index.js +0 -9
- package/dist/principal.d.ts +0 -44
- package/dist/principal.js +0 -49
- package/dist/react/SyncGroupProvider.d.ts +0 -19
- package/dist/react/SyncGroupProvider.js +0 -44
- package/dist/react/useClaim.d.ts +0 -29
- package/dist/react/useClaim.js +0 -42
- package/dist/react/usePresence.d.ts +0 -32
- package/dist/react/usePresence.js +0 -41
package/dist/cli.cjs
CHANGED
|
@@ -276803,7 +276803,8 @@ var ERROR_CODES = {
|
|
|
276803
276803
|
malformed_subscription: wire("validation", 400, false, "The update_subscription payload was malformed; expected { syncGroups: string[] }."),
|
|
276804
276804
|
model_claimed: wire("claim", 409, false, "The model instance is claimed by another participant."),
|
|
276805
276805
|
model_claimed_timeout: wire("claim", 409, false, "Timed out waiting for a model claim to clear."),
|
|
276806
|
-
model_claim_not_configured: client("claim", "Claiming
|
|
276806
|
+
model_claim_not_configured: client("claim", "Claiming requires the collaboration runtime, which the standard Ablo({ schema, apiKey }) client wires up for every model automatically \u2014 there is no per-model claim configuration to add. This appears only when a model proxy is constructed directly without that runtime (an internal/advanced path)."),
|
|
276807
|
+
model_watch_not_configured: client("claim", "watch() opens a presence/claim subscription and needs a live WebSocket, so it is unavailable on the HTTP transport and on model proxies built without a socket. Use the standard Ablo({ schema, apiKey }) client (default WebSocket transport)."),
|
|
276807
276808
|
// ── stale context / idempotency (409) ──────────────────────────────
|
|
276808
276809
|
stale_context: wire("conflict", 409, true, "The write carried a readAt watermark that is now stale; re-read and retry."),
|
|
276809
276810
|
idempotency_conflict: wire("conflict", 409, false, "The same Idempotency-Key was reused with a different request body."),
|
|
@@ -276855,6 +276856,7 @@ var ERROR_CODES = {
|
|
|
276855
276856
|
schema_scope_kind_invalid: wire("schema", 400, false, "A scope kind in the schema is invalid."),
|
|
276856
276857
|
schema_field_not_camelcase: wire("schema", 400, false, "A schema field name is not camelCase."),
|
|
276857
276858
|
schema_field_consecutive_caps: wire("schema", 400, false, "A schema field name has consecutive capital letters."),
|
|
276859
|
+
schema_reserved_field: client("schema", "A model redeclared a reserved base field (id, createdAt, updatedAt, organizationId, createdBy) that the SDK provides automatically."),
|
|
276858
276860
|
schema_grants_shape_invalid: wire("schema", 400, false, "A grants declaration has an invalid shape."),
|
|
276859
276861
|
schema_grants_identifier_unsafe: wire("schema", 400, false, "A grants declaration referenced an unsafe identifier."),
|
|
276860
276862
|
schema_grants_relation_kind: wire("schema", 400, false, "A grants relation referenced an invalid kind."),
|
|
@@ -279616,6 +279618,23 @@ var import_source = require("@abloatai/ablo/source");
|
|
|
279616
279618
|
// src/cli/push.ts
|
|
279617
279619
|
init_cjs_shims();
|
|
279618
279620
|
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
279621
|
+
|
|
279622
|
+
// src/auth/credentialPolicy.ts
|
|
279623
|
+
init_cjs_shims();
|
|
279624
|
+
var KIND_BY_PREFIX = [
|
|
279625
|
+
["sk_", "secret"],
|
|
279626
|
+
["ek_", "ephemeral"],
|
|
279627
|
+
["rk_", "restricted"],
|
|
279628
|
+
["pk_", "publishable"]
|
|
279629
|
+
];
|
|
279630
|
+
function classifyCredentialKind(value) {
|
|
279631
|
+
for (const [prefix, kind] of KIND_BY_PREFIX) {
|
|
279632
|
+
if (value.startsWith(prefix)) return kind;
|
|
279633
|
+
}
|
|
279634
|
+
return null;
|
|
279635
|
+
}
|
|
279636
|
+
|
|
279637
|
+
// src/cli/push.ts
|
|
279619
279638
|
var import_fs4 = require("fs");
|
|
279620
279639
|
var import_path3 = require("path");
|
|
279621
279640
|
var import_schema2 = require("@abloatai/ablo/schema");
|
|
@@ -279928,7 +279947,7 @@ async function push(argv) {
|
|
|
279928
279947
|
console.error(import_picocolors3.default.dim(` Re-push with ${import_picocolors3.default.bold("--force")} to override, or use ${import_picocolors3.default.bold("--rename old:new")} if you renamed a model.`));
|
|
279929
279948
|
} else if (status2 === 403) {
|
|
279930
279949
|
console.error(import_picocolors3.default.red(` Forbidden: ${body.message ?? body.reason ?? "key lacks schema:push scope"}`));
|
|
279931
|
-
if (args.apiKey
|
|
279950
|
+
if (args.apiKey != null && classifyCredentialKind(args.apiKey) === "restricted") {
|
|
279932
279951
|
console.error(
|
|
279933
279952
|
import_picocolors3.default.dim(
|
|
279934
279953
|
` Schema pushes need a SECRET key: ${import_picocolors3.default.bold("sk_test_")} (sandbox dev loop) or a dashboard ${import_picocolors3.default.bold("sk_live_")} (production deploy: ${import_picocolors3.default.bold("ABLO_API_KEY=sk_live_\u2026 npx ablo push")}).`
|
|
@@ -279942,6 +279961,14 @@ async function push(argv) {
|
|
|
279942
279961
|
}
|
|
279943
279962
|
|
|
279944
279963
|
// src/cli/migrate.ts
|
|
279964
|
+
var MIGRATE_USAGE = ` ablo migrate \u2014 provision your schema's tables in your own Postgres (DATABASE_URL)
|
|
279965
|
+
|
|
279966
|
+
Usage:
|
|
279967
|
+
npx ablo migrate Create the synced-model tables (with row-level security)
|
|
279968
|
+
npx ablo migrate --dry-run Print the SQL without executing it
|
|
279969
|
+
npx ablo migrate --output schema.sql Write the SQL to a file instead of applying
|
|
279970
|
+
npx ablo migrate --schema <path> Use a schema file other than ablo/schema.ts
|
|
279971
|
+
npx ablo migrate --export <name> Use a named export other than \`schema\``;
|
|
279945
279972
|
var DEFAULT_SCHEMA_PATH2 = "ablo/schema.ts";
|
|
279946
279973
|
var DEFAULT_EXPORT2 = "schema";
|
|
279947
279974
|
function parseMigrateArgs(argv) {
|
|
@@ -280215,7 +280242,7 @@ function classifyKey(apiKey, activeMode) {
|
|
|
280215
280242
|
reason: `Production schema deploys run one-shot: ${import_picocolors6.default.bold("ABLO_API_KEY=sk_live_\u2026 npx ablo push")} (or ${import_picocolors6.default.bold("ablo mode production")}). ${import_picocolors6.default.bold("--watch")} is sandbox-only.`
|
|
280216
280243
|
};
|
|
280217
280244
|
}
|
|
280218
|
-
if (apiKey
|
|
280245
|
+
if (classifyCredentialKind(apiKey) === "restricted") {
|
|
280219
280246
|
return {
|
|
280220
280247
|
ok: false,
|
|
280221
280248
|
reason: `Restricted (${import_picocolors6.default.bold("rk_")}) keys can't push schema. Use a secret key: ${import_picocolors6.default.bold("sk_test_")} for the sandbox dev loop, or ${import_picocolors6.default.bold("sk_live_")} with ${import_picocolors6.default.bold("npx ablo push")} for a production deploy.`
|
|
@@ -280478,7 +280505,10 @@ ${import_picocolors7.default.dim(url)}`, "Approve in your browser");
|
|
|
280478
280505
|
s.message("Provisioning a sandbox key\u2026");
|
|
280479
280506
|
const provRes = await fetch(`${AUTH_URL}/api/cli/provision-key`, {
|
|
280480
280507
|
method: "POST",
|
|
280481
|
-
headers: { authorization: `Bearer ${accessToken}
|
|
280508
|
+
headers: { authorization: `Bearer ${accessToken}`, "content-type": "application/json" },
|
|
280509
|
+
// Pass the device_code so the server can scope the minted keys to the
|
|
280510
|
+
// project the user picked at /cli (login project picker). Harmless if none.
|
|
280511
|
+
body: JSON.stringify({ device_code: code.device_code })
|
|
280482
280512
|
}).catch(() => null);
|
|
280483
280513
|
if (!provRes || !provRes.ok) {
|
|
280484
280514
|
s.stop("Could not provision a key.");
|
|
@@ -280706,6 +280736,39 @@ async function projects(argv) {
|
|
|
280706
280736
|
);
|
|
280707
280737
|
return;
|
|
280708
280738
|
}
|
|
280739
|
+
if (sub === "rename") {
|
|
280740
|
+
const ref = argv[1];
|
|
280741
|
+
const name = argv.slice(2).join(" ").trim();
|
|
280742
|
+
if (!ref || ref.startsWith("-") || !name) {
|
|
280743
|
+
console.error(import_picocolors9.default.red(" usage: ablo projects rename <slug|id> <new name>"));
|
|
280744
|
+
process.exit(1);
|
|
280745
|
+
}
|
|
280746
|
+
const all = await fetchProjects();
|
|
280747
|
+
const target = all.find((p2) => p2.slug === ref || p2.id === ref);
|
|
280748
|
+
if (!target) {
|
|
280749
|
+
console.error(import_picocolors9.default.red(` No project "${ref}".`) + import_picocolors9.default.dim(" Run ablo projects list."));
|
|
280750
|
+
process.exit(1);
|
|
280751
|
+
}
|
|
280752
|
+
if (target.default) {
|
|
280753
|
+
console.error(import_picocolors9.default.red(" The default project cannot be renamed."));
|
|
280754
|
+
process.exit(1);
|
|
280755
|
+
}
|
|
280756
|
+
const { status: status2, body } = await request(`/api/v1/projects/${target.id}`, requireKey(), {
|
|
280757
|
+
method: "PATCH",
|
|
280758
|
+
body: { name }
|
|
280759
|
+
});
|
|
280760
|
+
if (status2 !== 200) {
|
|
280761
|
+
console.error(
|
|
280762
|
+
import_picocolors9.default.red(` Rename failed (${status2}): ${String(body.message ?? body.code ?? "")}`)
|
|
280763
|
+
);
|
|
280764
|
+
process.exit(1);
|
|
280765
|
+
}
|
|
280766
|
+
const updated = body;
|
|
280767
|
+
console.log(
|
|
280768
|
+
` ${import_picocolors9.default.green("\u2713")} Renamed ${import_picocolors9.default.bold(updated.slug)} \u2192 ${import_picocolors9.default.bold(updated.name ?? updated.slug)} ${import_picocolors9.default.dim(`(${updated.id})`)}`
|
|
280769
|
+
);
|
|
280770
|
+
return;
|
|
280771
|
+
}
|
|
280709
280772
|
if (sub === "use") {
|
|
280710
280773
|
const ref = argv[1];
|
|
280711
280774
|
if (!ref) {
|
|
@@ -280733,7 +280796,9 @@ async function projects(argv) {
|
|
|
280733
280796
|
return;
|
|
280734
280797
|
}
|
|
280735
280798
|
console.error(
|
|
280736
|
-
import_picocolors9.default.red(` unknown subcommand: ${sub}`) + import_picocolors9.default.dim(
|
|
280799
|
+
import_picocolors9.default.red(` unknown subcommand: ${sub}`) + import_picocolors9.default.dim(
|
|
280800
|
+
` (expected ${import_picocolors9.default.bold("list")}, ${import_picocolors9.default.bold("create")}, ${import_picocolors9.default.bold("rename")}, or ${import_picocolors9.default.bold("use")})`
|
|
280801
|
+
)
|
|
280737
280802
|
);
|
|
280738
280803
|
process.exit(1);
|
|
280739
280804
|
}
|
|
@@ -281006,7 +281071,7 @@ function requireKey2(mode2) {
|
|
|
281006
281071
|
);
|
|
281007
281072
|
process.exit(1);
|
|
281008
281073
|
}
|
|
281009
|
-
if (
|
|
281074
|
+
if (classifyCredentialKind(apiKey) !== "secret") {
|
|
281010
281075
|
console.error(import_picocolors12.default.red(" Managing webhooks requires a secret key ") + import_picocolors12.default.dim("(sk_test_ / sk_live_)."));
|
|
281011
281076
|
process.exit(1);
|
|
281012
281077
|
}
|
|
@@ -282130,8 +282195,18 @@ async function drizzlePull(argv) {
|
|
|
282130
282195
|
var LOGO = `
|
|
282131
282196
|
${brand("ablo")} ${import_picocolors18.default.dim("sync engine")}
|
|
282132
282197
|
`;
|
|
282198
|
+
var SUBCOMMAND_USAGE = {
|
|
282199
|
+
migrate: MIGRATE_USAGE
|
|
282200
|
+
};
|
|
282133
282201
|
async function main() {
|
|
282134
|
-
|
|
282202
|
+
let command = process.argv[2];
|
|
282203
|
+
if (command && process.argv.slice(3).some((a) => a === "--help" || a === "-h")) {
|
|
282204
|
+
if (SUBCOMMAND_USAGE[command]) {
|
|
282205
|
+
console.log(SUBCOMMAND_USAGE[command]);
|
|
282206
|
+
return;
|
|
282207
|
+
}
|
|
282208
|
+
command = void 0;
|
|
282209
|
+
}
|
|
282135
282210
|
if (command === "init") {
|
|
282136
282211
|
await init(process.argv.slice(3));
|
|
282137
282212
|
} else if (command === "login") {
|
|
@@ -282149,8 +282224,14 @@ async function main() {
|
|
|
282149
282224
|
} else if (command === "webhooks") {
|
|
282150
282225
|
await webhooks(process.argv.slice(3));
|
|
282151
282226
|
} else if (command === "dev") {
|
|
282152
|
-
|
|
282153
|
-
|
|
282227
|
+
const devArgs = process.argv.slice(3);
|
|
282228
|
+
const oneShot = devArgs.includes("--no-watch");
|
|
282229
|
+
console.log(
|
|
282230
|
+
import_picocolors18.default.dim(
|
|
282231
|
+
oneShot ? " `ablo dev --no-watch` is `ablo push` (push once, no watcher) \u2014 running that." : " `ablo dev` is now `ablo push --watch` \u2014 running that."
|
|
282232
|
+
)
|
|
282233
|
+
);
|
|
282234
|
+
await dev(oneShot ? devArgs : [...devArgs, "--watch"]);
|
|
282154
282235
|
} else if (command === "check") {
|
|
282155
282236
|
await check(process.argv.slice(3));
|
|
282156
282237
|
} else if (command === "pull") {
|
|
@@ -282208,6 +282289,8 @@ async function main() {
|
|
|
282208
282289
|
console.log(` npx ablo pull prisma [path] Generate schema.ts from a Prisma schema (keeps enums + relations)`);
|
|
282209
282290
|
console.log(` npx ablo pull drizzle <module> Generate schema.ts from a Drizzle schema (keeps enums + relations)`);
|
|
282210
282291
|
console.log(` npx ablo check Check your existing database fits the schema (read-only, creates no tables)`);
|
|
282292
|
+
console.log(` npx ablo migrate Provision your synced-model tables in your own Postgres (DATABASE_URL)`);
|
|
282293
|
+
console.log(` npx ablo migrate --dry-run Print the SQL without executing (preview)`);
|
|
282211
282294
|
console.log(` npx ablo push Upload your schema definition to Ablo (metadata only \u2014 rows stay in your DB)`);
|
|
282212
282295
|
console.log(` npx ablo push --force Allow destructive/unexecutable changes`);
|
|
282213
282296
|
console.log(` npx ablo push --rename a:b Treat model "a" as renamed to "b"`);
|
|
@@ -282285,6 +282368,10 @@ function detectOrm(override) {
|
|
|
282285
282368
|
}
|
|
282286
282369
|
return "none";
|
|
282287
282370
|
}
|
|
282371
|
+
function detectNextLayout() {
|
|
282372
|
+
const useSrc = (0, import_fs12.existsSync)((0, import_path7.join)("src", "app")) || !(0, import_fs12.existsSync)("app") && (0, import_fs12.existsSync)("src");
|
|
282373
|
+
return useSrc ? { appBase: (0, import_path7.join)("src", "app"), aliasBase: "src" } : { appBase: "app", aliasBase: "." };
|
|
282374
|
+
}
|
|
282288
282375
|
async function chooseOption(name, flagValue, fallback, allowed, interactive, prompt) {
|
|
282289
282376
|
if (flagValue !== void 0) {
|
|
282290
282377
|
if (!allowed.includes(flagValue)) {
|
|
@@ -282384,7 +282471,8 @@ async function init(args = []) {
|
|
|
282384
282471
|
"Non-interactive (no TTY / --yes)"
|
|
282385
282472
|
);
|
|
282386
282473
|
}
|
|
282387
|
-
const
|
|
282474
|
+
const layout = framework === "nextjs" ? detectNextLayout() : { appBase: "app", aliasBase: "." };
|
|
282475
|
+
const abloDir = (0, import_path7.join)(layout.aliasBase, "ablo");
|
|
282388
282476
|
(0, import_fs12.mkdirSync)(abloDir, { recursive: true });
|
|
282389
282477
|
const created = [];
|
|
282390
282478
|
let schemaSource = generateSchema();
|
|
@@ -282415,41 +282503,51 @@ async function init(args = []) {
|
|
|
282415
282503
|
created.push(`${abloDir}/schema.ts${schemaNote}`);
|
|
282416
282504
|
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "index.ts"), generateSyncConfig(auth, storage));
|
|
282417
282505
|
created.push(`${abloDir}/index.ts`);
|
|
282506
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "register.ts"), generateRegister());
|
|
282507
|
+
created.push(`${abloDir}/register.ts`);
|
|
282418
282508
|
const orm = detectOrm(opts.orm);
|
|
282419
282509
|
if (storage === "endpoint") {
|
|
282420
282510
|
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "data-source.ts"), generateDataSource(orm));
|
|
282421
282511
|
created.push(`${abloDir}/data-source.ts${orm === "drizzle" ? " (Drizzle)" : " (Prisma)"}`);
|
|
282422
282512
|
}
|
|
282423
282513
|
const envFile = framework === "nextjs" ? ".env.local" : ".env";
|
|
282514
|
+
const resolvedKey = process.env.ABLO_API_KEY ? void 0 : resolveApiKey("sandbox");
|
|
282515
|
+
const wireRealKey = envFile === ".env.local" && Boolean(resolvedKey);
|
|
282516
|
+
const envBody = generateEnv(storage, { includeApiKey: !wireRealKey });
|
|
282424
282517
|
if (!(0, import_fs12.existsSync)(envFile)) {
|
|
282425
|
-
(0, import_fs12.writeFileSync)(envFile,
|
|
282518
|
+
(0, import_fs12.writeFileSync)(envFile, envBody);
|
|
282426
282519
|
created.push(envFile);
|
|
282427
282520
|
} else {
|
|
282428
282521
|
const existing = (0, import_fs12.readFileSync)(envFile, "utf-8");
|
|
282429
282522
|
if (!existing.includes("ABLO_")) {
|
|
282430
|
-
(0, import_fs12.writeFileSync)(envFile, existing + "\n" +
|
|
282523
|
+
(0, import_fs12.writeFileSync)(envFile, existing + "\n" + envBody);
|
|
282431
282524
|
created.push(`${envFile} ${import_picocolors18.default.dim("(appended)")}`);
|
|
282432
282525
|
} else {
|
|
282433
282526
|
created.push(`${envFile} ${import_picocolors18.default.dim("(already configured)")}`);
|
|
282434
282527
|
}
|
|
282435
282528
|
}
|
|
282529
|
+
if (wireRealKey && resolvedKey) {
|
|
282530
|
+
wireEnvLocal(resolvedKey);
|
|
282531
|
+
created.push(`.env.local ${import_picocolors18.default.dim("(ABLO_API_KEY set from your login)")}`);
|
|
282532
|
+
}
|
|
282436
282533
|
if (agent) {
|
|
282437
282534
|
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "agent.ts"), generateAgent());
|
|
282438
282535
|
created.push(`${abloDir}/agent.ts`);
|
|
282439
282536
|
}
|
|
282440
282537
|
if (framework === "nextjs") {
|
|
282441
282538
|
if (storage === "endpoint") {
|
|
282442
|
-
const webhookDir = (0, import_path7.join)(
|
|
282539
|
+
const webhookDir = (0, import_path7.join)(layout.appBase, "api", "ablo", "webhooks");
|
|
282443
282540
|
(0, import_fs12.mkdirSync)(webhookDir, { recursive: true });
|
|
282444
282541
|
(0, import_fs12.writeFileSync)((0, import_path7.join)(webhookDir, "route.ts"), generateWebhookRoute(orm));
|
|
282445
282542
|
created.push(`${webhookDir}/route.ts${orm === "prisma" ? " (Prisma mirror)" : " (add your database write)"}`);
|
|
282446
282543
|
}
|
|
282447
|
-
|
|
282448
|
-
|
|
282449
|
-
|
|
282544
|
+
const providersPath = (0, import_path7.join)(layout.appBase, "providers.tsx");
|
|
282545
|
+
(0, import_fs12.writeFileSync)(providersPath, generateProviders());
|
|
282546
|
+
created.push(`${providersPath} ${import_picocolors18.default.dim(`(wrap ${(0, import_path7.join)(layout.appBase, "layout.tsx")} in <Providers>)`)}`);
|
|
282547
|
+
const sessionDir = (0, import_path7.join)(layout.appBase, "api", "ablo-session");
|
|
282450
282548
|
(0, import_fs12.mkdirSync)(sessionDir, { recursive: true });
|
|
282451
282549
|
(0, import_fs12.writeFileSync)((0, import_path7.join)(sessionDir, "route.ts"), generateSessionRoute());
|
|
282452
|
-
created.push(
|
|
282550
|
+
created.push(`${(0, import_path7.join)(sessionDir, "route.ts")} ${import_picocolors18.default.dim("(wire your auth)")}`);
|
|
282453
282551
|
}
|
|
282454
282552
|
if (framework !== "vanilla") {
|
|
282455
282553
|
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "TaskList.tsx"), generateComponent());
|
|
@@ -282478,7 +282576,7 @@ async function init(args = []) {
|
|
|
282478
282576
|
`Provision your DB: ${import_picocolors18.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors18.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors18.default.bold("/api/ablo/source")}`
|
|
282479
282577
|
],
|
|
282480
282578
|
...framework === "nextjs" ? [
|
|
282481
|
-
`Wrap ${import_picocolors18.default.bold("
|
|
282579
|
+
`Wrap ${import_picocolors18.default.bold((0, import_path7.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors18.default.bold("<Providers>")} (${(0, import_path7.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors18.default.bold((0, import_path7.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
|
|
282482
282580
|
] : [],
|
|
282483
282581
|
`Run ${import_picocolors18.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
|
|
282484
282582
|
...agent ? [
|
|
@@ -282557,14 +282655,31 @@ export const sync = Ablo({
|
|
|
282557
282655
|
apiKey: process.env.ABLO_API_KEY,${databaseLine}${authLine}
|
|
282558
282656
|
schema,
|
|
282559
282657
|
});
|
|
282658
|
+
|
|
282659
|
+
// Name the client's type off the constructed value \u2014 the overload resolves at
|
|
282660
|
+
// this call site, so this carries the full typed surface. (Like tRPC's
|
|
282661
|
+
// \`typeof appRouter\`, Drizzle's \`typeof db\`.) Prefer this over \`ReturnType<typeof Ablo>\`.
|
|
282662
|
+
export type Sync = typeof sync;
|
|
282663
|
+
`;
|
|
282664
|
+
}
|
|
282665
|
+
function generateRegister() {
|
|
282666
|
+
return `import type { schema } from './schema';
|
|
282667
|
+
|
|
282668
|
+
declare module '@abloatai/ablo' {
|
|
282669
|
+
interface Register {
|
|
282670
|
+
Schema: typeof schema;
|
|
282671
|
+
}
|
|
282672
|
+
}
|
|
282673
|
+
|
|
282674
|
+
export {};
|
|
282560
282675
|
`;
|
|
282561
282676
|
}
|
|
282562
|
-
function generateEnv(storage) {
|
|
282677
|
+
function generateEnv(storage, opts = {}) {
|
|
282678
|
+
const { includeApiKey = true } = opts;
|
|
282563
282679
|
const databaseBlock = storage === "direct" ? "# Your Postgres \u2014 the system of record. The client registers this connection\n# (sent once over TLS, stored sealed) and every row lives HERE, never with Ablo.\n# Use a dedicated non-superuser role; the browser never sees this value.\nDATABASE_URL=postgres://user:password@host:5432/db\n" : "# Used by ablo/data-source.ts (your DB endpoint) + `ablo migrate` \u2014 NOT the client.\n# Ablo never sees it; the browser never sees it. Your DB stays in your app.\nDATABASE_URL=postgres://user:password@host:5432/db\n";
|
|
282564
282680
|
const webhookBlock = storage === "endpoint" ? "# Signing secret for the webhook receiver (app/api/ablo/webhooks/route.ts).\n# Ablo mints this when you register the endpoint's URL (POST /v1/webhook_endpoints\n# or the dashboard) and returns it once \u2014 paste it here.\nABLO_WEBHOOK_SECRET=whsec_your_endpoint_secret_here\n" : "";
|
|
282565
|
-
|
|
282566
|
-
|
|
282567
|
-
${webhookBlock}${databaseBlock}`;
|
|
282681
|
+
const apiKeyBlock = includeApiKey ? "# Ablo Sync Engine \u2014 use a sk_test_ key for local dev (`npx ablo push`)\nABLO_API_KEY=sk_test_your_key_here\n" : "";
|
|
282682
|
+
return `${apiKeyBlock}${webhookBlock}${databaseBlock}`;
|
|
282568
282683
|
}
|
|
282569
282684
|
function generateDataSource(orm) {
|
|
282570
282685
|
return orm === "drizzle" ? drizzleDataSourceScaffold() : prismaDataSourceScaffold();
|
|
@@ -282826,9 +282941,23 @@ import Ablo from '@abloatai/ablo';
|
|
|
282826
282941
|
import { AbloProvider } from '@abloatai/ablo/react';
|
|
282827
282942
|
import { schema } from '@/ablo/schema';
|
|
282828
282943
|
|
|
282829
|
-
// The browser client holds NO secret. \`
|
|
282830
|
-
// which mints a short-lived session token (already scoped to the org +
|
|
282831
|
-
|
|
282944
|
+
// The browser client holds NO secret. The \`apiKey\` resolver fetches the route
|
|
282945
|
+
// below, which mints a short-lived session token (already scoped to the org +
|
|
282946
|
+
// user); the client keeps it fresh (refresh timer + wake/online/focus re-mint).
|
|
282947
|
+
// Contract: return the token, return \`null\` when the user is signed out
|
|
282948
|
+
// (\u2192 the client signs out), or throw on a transient failure (\u2192 it retries).
|
|
282949
|
+
const ablo = Ablo({
|
|
282950
|
+
schema,
|
|
282951
|
+
apiKey: async () => {
|
|
282952
|
+
const res = await fetch('/api/ablo-session', {
|
|
282953
|
+
method: 'POST',
|
|
282954
|
+
credentials: 'include',
|
|
282955
|
+
});
|
|
282956
|
+
if (!res.ok) return null;
|
|
282957
|
+
const { token } = (await res.json()) as { token: string | null };
|
|
282958
|
+
return token;
|
|
282959
|
+
},
|
|
282960
|
+
});
|
|
282832
282961
|
|
|
282833
282962
|
export function Providers({ children }: { children: React.ReactNode }) {
|
|
282834
282963
|
return <AbloProvider client={ablo}>{children}</AbloProvider>;
|
package/dist/client/Ablo.d.ts
CHANGED
|
@@ -28,7 +28,6 @@ import type { SyncWebSocket } from '../sync/SyncWebSocket.js';
|
|
|
28
28
|
import type { SyncGroupInput } from '../schema/roles.js';
|
|
29
29
|
import { type SyncStatus } from '../BaseSyncedStore.js';
|
|
30
30
|
import type { ClaimStream, ClaimWaitOptions, PresenceStream, Snapshot } from '../types/streams.js';
|
|
31
|
-
import type { ParticipantManager } from '../sync/participants.js';
|
|
32
31
|
import type { ClaimHandle, Duration, Claim } from '../types/streams.js';
|
|
33
32
|
import { type AbloApi, type AbloApiClientOptions, type AbloApiClaims } from './ApiClient.js';
|
|
34
33
|
import { type AbloHttpClient, type AbloHttpClientOptions } from './httpClient.js';
|
|
@@ -77,35 +76,24 @@ export interface AbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
77
76
|
* usually pass nothing). A long-lived key needs no refresh; the client uses
|
|
78
77
|
* it as-is.
|
|
79
78
|
*
|
|
80
|
-
* Accepts a static string
|
|
81
|
-
*
|
|
79
|
+
* Accepts a static string OR an async `() => Promise<string | null>` resolver
|
|
80
|
+
* — the single credential path. Use the resolver form for two cases:
|
|
82
81
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
*
|
|
91
|
-
* fresh bearer (`ek_`/`rk_`) your backend minted for the signed-in user. The
|
|
92
|
-
* client calls it once before connect and then keeps the key fresh for you —
|
|
93
|
-
* a refresh timer ahead of expiry plus re-mint on OS-wake / network-online /
|
|
94
|
-
* tab-focus, and a reactive re-mint when a probe finds the key stale. You
|
|
95
|
-
* never call a refresh method (Supabase `autoRefreshToken` model).
|
|
82
|
+
* - **Key rotation** (server): pull a fresh `sk_`/`pk_` from a vault on each
|
|
83
|
+
* bootstrap (AWS STS, GCP IAM, Vault).
|
|
84
|
+
* - **Short-lived per-user browser** auth: return the fresh `ek_`/`rk_` bearer
|
|
85
|
+
* your backend minted for the signed-in user. The client mints once before
|
|
86
|
+
* connect, then keeps it fresh for you — a refresh timer ahead of expiry
|
|
87
|
+
* plus re-mint on OS-wake / network-online / tab-focus, and a reactive
|
|
88
|
+
* re-mint when a probe finds the key stale. You never call a refresh method
|
|
89
|
+
* (Supabase `autoRefreshToken` model).
|
|
96
90
|
*
|
|
97
|
-
*
|
|
98
|
-
* (terminal →
|
|
99
|
-
*
|
|
100
|
-
|
|
101
|
-
getToken?: (() => Promise<string | null>) | undefined;
|
|
102
|
-
/**
|
|
103
|
-
* Convenience over {@link getToken}: a URL on YOUR backend that returns
|
|
104
|
-
* `{ token }`. The client POSTs to it (with cookies, so it's authed by the
|
|
105
|
-
* user's session) to mint + refresh the bearer. Ignored when `getToken` is
|
|
106
|
-
* set. Pure sugar — `getToken: () => fetch(url).then(r => r.json()).then(b => b.token)`.
|
|
91
|
+
* Resolver contract: resolve a token; resolve `null` when the login itself is
|
|
92
|
+
* gone (terminal → the client signs out / fails `ready()` with `session_expired`);
|
|
93
|
+
* or THROW on a transient failure (→ back off and retry, never sign out). A
|
|
94
|
+
* static string never refreshes — it is used as-is.
|
|
107
95
|
*/
|
|
108
|
-
|
|
96
|
+
apiKey?: string | ApiKeySetter | null | undefined;
|
|
109
97
|
/**
|
|
110
98
|
* Direct-URL convenience connector: a connection string to your own Postgres
|
|
111
99
|
* that Ablo can register for a dedicated tenant.
|
|
@@ -138,6 +126,9 @@ export interface AbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
138
126
|
* `AbloHttpClient<S>`, so stateful-only capabilities (`get`/`getAll`,
|
|
139
127
|
* `onChange`) are compile errors rather than latent runtime gaps.
|
|
140
128
|
*
|
|
129
|
+
* Note: session/credential minting (`sessions.create`) currently runs on the
|
|
130
|
+
* stateful (default) client, not the http client.
|
|
131
|
+
*
|
|
141
132
|
* @default 'websocket'
|
|
142
133
|
*/
|
|
143
134
|
transport?: 'websocket' | 'http' | undefined;
|
|
@@ -225,18 +216,6 @@ export interface InternalAbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
225
216
|
* only for the advanced Model / Claim / Commit client.
|
|
226
217
|
*/
|
|
227
218
|
schema: Schema<S>;
|
|
228
|
-
/**
|
|
229
|
-
* Short-lived-bearer resolver for the per-user browser path (mirrors the
|
|
230
|
-
* public {@link AbloOptions.getToken}). The client mints the first token
|
|
231
|
-
* before connect and refreshes it (timer + wake/online/focus) — see
|
|
232
|
-
* {@link resolveCredentialResolver}.
|
|
233
|
-
*/
|
|
234
|
-
getToken?: (() => Promise<string | null>) | undefined;
|
|
235
|
-
/**
|
|
236
|
-
* Backend URL returning `{ token }`; sugar over {@link getToken}. Mirrors the
|
|
237
|
-
* public {@link AbloOptions.authEndpoint}.
|
|
238
|
-
*/
|
|
239
|
-
authEndpoint?: string | undefined;
|
|
240
219
|
/**
|
|
241
220
|
* @deprecated Server derives participant kind from the apiKey's
|
|
242
221
|
* scope. Pass apiKey only; this option will be removed once the
|
|
@@ -385,8 +364,8 @@ export interface InternalAbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
385
364
|
* `create({ data })` / `update({ id, data })` / `delete({ id })` — writes
|
|
386
365
|
* `claim({ id })` — durable claim handle for coordinated writes
|
|
387
366
|
*/
|
|
388
|
-
export type {
|
|
389
|
-
import type { ModelOperations, ClaimOptions, ClaimParams, ClaimLookupParams, ClaimReorderParams,
|
|
367
|
+
export type { LocalCountOptions, LocalReadOptions, ModelListScope, ServerReadOptions, ModelRetrieveParams, ModelCreateParams, ModelUpdateParams, ModelDeleteParams, ClaimOptions, ClaimParams, ClaimLookupParams, ClaimReorderParams, ClaimHandle, ModelOperations, } from './createModelProxy.js';
|
|
368
|
+
import type { ModelOperations, ClaimOptions, ClaimParams, ClaimLookupParams, ClaimReorderParams, ServerReadOptions } from './createModelProxy.js';
|
|
390
369
|
export type ModelOperationAction = 'create' | 'update' | 'delete' | 'archive' | 'unarchive';
|
|
391
370
|
export type CommitWait = 'queued' | 'confirmed';
|
|
392
371
|
export interface ModelRead<T = Record<string, unknown>> {
|
|
@@ -394,23 +373,15 @@ export interface ModelRead<T = Record<string, unknown>> {
|
|
|
394
373
|
readonly stamp: number;
|
|
395
374
|
readonly claims: readonly ModelClaim[];
|
|
396
375
|
}
|
|
397
|
-
export type IfClaimedPolicy = 'return' | '
|
|
376
|
+
export type IfClaimedPolicy = 'return' | 'fail';
|
|
398
377
|
export interface ClaimedOptions {
|
|
399
378
|
/**
|
|
400
|
-
* What to do when another participant has claimed the target
|
|
401
|
-
* includes active claim metadata in the response
|
|
402
|
-
* claim
|
|
379
|
+
* What to do when another participant has claimed the target: `return`
|
|
380
|
+
* includes active claim metadata in the response; `fail` throws
|
|
381
|
+
* `AbloClaimedError`. Waiting for a claim to clear is a claim-side concern —
|
|
382
|
+
* take `ablo.<model>.claim({ id })` (it queues fairly); reads never block.
|
|
403
383
|
*/
|
|
404
384
|
readonly ifClaimed?: IfClaimedPolicy;
|
|
405
|
-
/** Max time to wait for peer claims to clear, in milliseconds. */
|
|
406
|
-
readonly claimedTimeout?: number;
|
|
407
|
-
/** HTTP API polling interval while waiting. WebSocket clients ignore it. */
|
|
408
|
-
readonly claimedPollInterval?: number;
|
|
409
|
-
/**
|
|
410
|
-
* Backpressure for `ifClaimed: 'wait'`: reject instead of waiting if the
|
|
411
|
-
* row's FIFO line is already `>= maxQueueDepth` deep.
|
|
412
|
-
*/
|
|
413
|
-
readonly maxQueueDepth?: number;
|
|
414
385
|
}
|
|
415
386
|
export type { ClaimWaitOptions } from '../types/streams.js';
|
|
416
387
|
export interface ModelReadOptions extends ClaimedOptions {
|
|
@@ -527,7 +498,7 @@ export interface ModelClient<T = Record<string, unknown>> {
|
|
|
527
498
|
* `limit`. Present on the stateless protocol client; the store-backed
|
|
528
499
|
* `.model(name)` accessor omits it (use the typed `ablo.<model>.list` there).
|
|
529
500
|
*/
|
|
530
|
-
list?(options?:
|
|
501
|
+
list?(options?: ServerReadOptions<T>): Promise<T[]>;
|
|
531
502
|
create(params: ModelMutationOptions & {
|
|
532
503
|
readonly data: Record<string, unknown>;
|
|
533
504
|
readonly id?: string | null;
|
|
@@ -560,7 +531,7 @@ export interface CreateUserSessionParams {
|
|
|
560
531
|
id: string;
|
|
561
532
|
};
|
|
562
533
|
/** Sync groups this session may subscribe to — typed (`'default'` or
|
|
563
|
-
* `<namespace>:<id>`; build with `syncGroup
|
|
534
|
+
* `<namespace>:<id>`; build with `syncGroup(kind, id)` from
|
|
564
535
|
* `@abloatai/ablo/schema`). Omit for the server default:
|
|
565
536
|
* `[org:<your org>, user:<user.id>]`. */
|
|
566
537
|
syncGroups?: readonly SyncGroupInput[];
|
|
@@ -585,7 +556,7 @@ export interface CreateAgentSessionParams<S extends SchemaRecord> {
|
|
|
585
556
|
[M in keyof S & string]?: readonly SessionOperation[];
|
|
586
557
|
};
|
|
587
558
|
/** Sync groups this session may subscribe to — typed (`'default'` or
|
|
588
|
-
* `<namespace>:<id>`; build with `syncGroup
|
|
559
|
+
* `<namespace>:<id>`; build with `syncGroup(kind, id)` from
|
|
589
560
|
* `@abloatai/ablo/schema`). Omit for the server default: the org
|
|
590
561
|
* anchor (`org:<your org>`) + the agent's own anchor. */
|
|
591
562
|
syncGroups?: readonly SyncGroupInput[];
|
|
@@ -667,7 +638,7 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
667
638
|
* Replace the bearer auth token used for the WebSocket upgrade and HTTP
|
|
668
639
|
* requests, WITHOUT tearing down the engine. Use to push a refreshed
|
|
669
640
|
* short-lived access key (the Stripe-style `ek_`/`rk_`) before it expires —
|
|
670
|
-
*
|
|
641
|
+
* the client's `apiKey`-resolver refresh loop calls this. Reuses the same
|
|
671
642
|
* rotation path as the internal capability-token refresh; safe to call before
|
|
672
643
|
* `ready()`. Also nudges a parked connection to re-probe with the new token.
|
|
673
644
|
*/
|
|
@@ -675,8 +646,8 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
675
646
|
/**
|
|
676
647
|
* Resolve the active bearer credential this engine authenticates with — the
|
|
677
648
|
* live `ek_`/`rk_` the WebSocket and HTTP transports currently carry (kept
|
|
678
|
-
* fresh by the `
|
|
679
|
-
* key. Returns `null` when no credential is set yet. Use it to authenticate
|
|
649
|
+
* fresh by the `apiKey`-resolver refresh loop), falling back to a configured
|
|
650
|
+
* API key. Returns `null` when no credential is set yet. Use it to authenticate
|
|
680
651
|
* a side-band request to the same server with the very token this client
|
|
681
652
|
* already holds — no extra mint round-trip.
|
|
682
653
|
*/
|
|
@@ -685,10 +656,10 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
685
656
|
* Register a re-mint hook for the short-lived access key. The connection
|
|
686
657
|
* layer calls it WHEN it finds the key stale (a `credential_stale` probe) or
|
|
687
658
|
* on an external nudge; the hook mints a fresh `ek_`/`rk_` from the still-valid
|
|
688
|
-
* login. Mirrors the `
|
|
689
|
-
* the login itself is gone (→ sign out), or THROW on a transient
|
|
690
|
-
* back off, never sign out).
|
|
691
|
-
* `
|
|
659
|
+
* login. Mirrors the `apiKey`-resolver contract: resolve a token, resolve
|
|
660
|
+
* `null` when the login itself is gone (→ sign out), or THROW on a transient
|
|
661
|
+
* failure (→ back off, never sign out). The client wires this automatically
|
|
662
|
+
* from a function `apiKey`. Safe to call before `ready()`.
|
|
692
663
|
*/
|
|
693
664
|
setCredentialRefresher(refresher: (() => Promise<string | null>) | null): void;
|
|
694
665
|
/**
|
|
@@ -703,14 +674,15 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
703
674
|
* Mint a short-lived, scoped **session token** for one end user — the
|
|
704
675
|
* Stripe `ephemeralKeys.create` / Supabase session shape. Call this on YOUR
|
|
705
676
|
* BACKEND (where the `sk_` secret key lives), then hand the returned
|
|
706
|
-
* `token` to that user's browser (typically via
|
|
707
|
-
* fetches). The browser presents it as the bearer; the sync-server verifies
|
|
677
|
+
* `token` to that user's browser (typically via a token route the browser's
|
|
678
|
+
* `apiKey` resolver fetches). The browser presents it as the bearer; the sync-server verifies
|
|
708
679
|
* it via `apiKeyProvider`.
|
|
709
680
|
*
|
|
710
681
|
* The browser must NEVER see the `sk_` key — only the per-user session token.
|
|
711
682
|
*
|
|
712
683
|
* Pass `{ user: { id } }` for a full-authority end-user session (mints `ek_`,
|
|
713
|
-
* `
|
|
684
|
+
* `participantKind: 'user'` attribution, stored as `actor_kind` on the delta
|
|
685
|
+
* row), or `{ agent: { id }, can: { tasks:
|
|
714
686
|
* ['update'] } }` for a scoped agent session (mints `rk_`); `can` is typed
|
|
715
687
|
* against your schema's model names. Always authenticates with the original
|
|
716
688
|
* `sk_` — never the client's exchanged sync credential.
|
|
@@ -822,24 +794,6 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
822
794
|
* are schema-powered sugar over the same model write/read path.
|
|
823
795
|
*/
|
|
824
796
|
model<T = Record<string, unknown>>(name: string): ModelClient<T>;
|
|
825
|
-
/**
|
|
826
|
-
* Canonical multiplayer participant surface. Joins a structured app
|
|
827
|
-
* target, derives the transport scope internally, opens a scoped
|
|
828
|
-
* claim on the existing WebSocket, and returns target-bound presence
|
|
829
|
-
* + claim helpers.
|
|
830
|
-
*
|
|
831
|
-
* ```ts
|
|
832
|
-
* const participant = await ablo.participants.join({
|
|
833
|
-
* type: 'File',
|
|
834
|
-
* id: 'src/foo.ts',
|
|
835
|
-
* path: 'src/foo.ts',
|
|
836
|
-
* range: { startLine: 10, endLine: 40 },
|
|
837
|
-
* });
|
|
838
|
-
* participant.presence.editing();
|
|
839
|
-
* const claim = participant.claims.claim('rewrite imports');
|
|
840
|
-
* ```
|
|
841
|
-
*/
|
|
842
|
-
readonly participants: ParticipantManager;
|
|
843
797
|
/**
|
|
844
798
|
* Capture a context-staleness watermark over a set of entities.
|
|
845
799
|
* Returns a flat snapshot with `stamp` (thread into writes as
|
|
@@ -991,9 +945,6 @@ export declare namespace Ablo {
|
|
|
991
945
|
type ClaimLost = _Streams.ClaimLost;
|
|
992
946
|
type Snapshot<TSchema extends _SchemaTypes.Schema = _SchemaTypes.Schema, K extends keyof TSchema['models'] = keyof TSchema['models']> = _Streams.Snapshot<TSchema, K>;
|
|
993
947
|
namespace Auth {
|
|
994
|
-
type Principal = _Streams.Principal;
|
|
995
|
-
type Session = _Streams.SessionRef;
|
|
996
|
-
type Agent = _Streams.AgentRef;
|
|
997
948
|
type Actor = _Streams.ParticipantRef;
|
|
998
949
|
}
|
|
999
950
|
namespace Participant {
|