@odla-ai/chapter 0.33.0 → 0.33.1
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/README.md +5 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/worker/index.cjs +10 -0
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.js +10 -0
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -445,6 +445,11 @@ join-config, application tier validation, and checkout already read. Public
|
|
|
445
445
|
application contract, and theme. Applicant requests therefore use local
|
|
446
446
|
last-known-good state and never depend on the hub being reachable.
|
|
447
447
|
|
|
448
|
+
The first delivery is empty-history safe: Chapter checks a bounded aggregate
|
|
449
|
+
count before asking odla-db to order revision history. A freshly provisioned
|
|
450
|
+
follower therefore acknowledges revision 1 immediately instead of depending on
|
|
451
|
+
an ordered query over an empty result set.
|
|
452
|
+
|
|
448
453
|
The hub owns a durable outbox: create/verify immutable Stripe Prices first,
|
|
449
454
|
persist the desired revision, retry signed delivery, and mark it active only
|
|
450
455
|
after the exact revision/digest receipt. Version history is for audit and
|
package/dist/index.d.cts
CHANGED
|
@@ -310,6 +310,16 @@ interface DbOp {
|
|
|
310
310
|
* member routes consume — so route logic is testable against an in-memory fake. */
|
|
311
311
|
interface ChapterDb {
|
|
312
312
|
query(q: Record<string, unknown>): Promise<Record<string, Array<Record<string, unknown>>>>;
|
|
313
|
+
/** Optional bounded aggregate supported by the real privileged odla-db
|
|
314
|
+
* client. Routes use it to prove a result set is non-empty before issuing
|
|
315
|
+
* an ordered lookup, while small test doubles may continue to omit it. */
|
|
316
|
+
aggregate?(ns: string, spec: {
|
|
317
|
+
count?: boolean;
|
|
318
|
+
}, opts?: {
|
|
319
|
+
where?: Record<string, unknown>;
|
|
320
|
+
}): Promise<{
|
|
321
|
+
count?: number;
|
|
322
|
+
}>;
|
|
313
323
|
transact(ops: DbOp[], opts?: {
|
|
314
324
|
mutationId?: string;
|
|
315
325
|
}): Promise<{
|
package/dist/index.d.ts
CHANGED
|
@@ -310,6 +310,16 @@ interface DbOp {
|
|
|
310
310
|
* member routes consume — so route logic is testable against an in-memory fake. */
|
|
311
311
|
interface ChapterDb {
|
|
312
312
|
query(q: Record<string, unknown>): Promise<Record<string, Array<Record<string, unknown>>>>;
|
|
313
|
+
/** Optional bounded aggregate supported by the real privileged odla-db
|
|
314
|
+
* client. Routes use it to prove a result set is non-empty before issuing
|
|
315
|
+
* an ordered lookup, while small test doubles may continue to omit it. */
|
|
316
|
+
aggregate?(ns: string, spec: {
|
|
317
|
+
count?: boolean;
|
|
318
|
+
}, opts?: {
|
|
319
|
+
where?: Record<string, unknown>;
|
|
320
|
+
}): Promise<{
|
|
321
|
+
count?: number;
|
|
322
|
+
}>;
|
|
313
323
|
transact(ops: DbOp[], opts?: {
|
|
314
324
|
mutationId?: string;
|
|
315
325
|
}): Promise<{
|
package/dist/worker/index.cjs
CHANGED
|
@@ -527,7 +527,16 @@ function asStored(row) {
|
|
|
527
527
|
if (!row || typeof row.document !== "object" || row.document === null) return null;
|
|
528
528
|
return row;
|
|
529
529
|
}
|
|
530
|
+
async function hasSignupControl(db, targetId, environment, active) {
|
|
531
|
+
const where = { targetId, environment, ...active ? { active: true } : {} };
|
|
532
|
+
if (db.aggregate) {
|
|
533
|
+
return Number((await db.aggregate("signupControls", { count: true }, { where })).count ?? 0) > 0;
|
|
534
|
+
}
|
|
535
|
+
const rows2 = (await db.query({ signupControls: {} })).signupControls;
|
|
536
|
+
return Array.isArray(rows2) && rows2.some((row) => row.targetId === targetId && row.environment === environment && (!active || row.active === true));
|
|
537
|
+
}
|
|
530
538
|
async function loadLatestSignupControl(db, targetId, environment) {
|
|
539
|
+
if (!await hasSignupControl(db, targetId, environment)) return null;
|
|
531
540
|
const rows2 = (await db.query({ signupControls: { $: {
|
|
532
541
|
where: { targetId, environment },
|
|
533
542
|
order: { revision: "desc" },
|
|
@@ -537,6 +546,7 @@ async function loadLatestSignupControl(db, targetId, environment) {
|
|
|
537
546
|
return asStored(latest);
|
|
538
547
|
}
|
|
539
548
|
async function loadActiveSignupControl(db, targetId, environment) {
|
|
549
|
+
if (!await hasSignupControl(db, targetId, environment, true)) return null;
|
|
540
550
|
const rows2 = (await db.query({ signupControls: { $: {
|
|
541
551
|
where: { targetId, environment, active: true },
|
|
542
552
|
order: { revision: "desc" },
|