@odla-ai/chapter 0.33.1 → 0.34.0
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.cjs +93 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -8
- package/dist/index.d.ts +37 -8
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -1
- package/dist/worker/index.cjs +34 -7
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.js +34 -7
- package/dist/worker/index.js.map +1 -1
- package/package.json +2 -1
- package/runbooks/greenfield.md +4 -0
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
|
+
Materialization addresses provisioned groups and tiers by their unique public
|
|
449
|
+
`id` attributes, not by assuming those values are odla-db entity ids. A failed
|
|
450
|
+
materialization returns a bounded JSON `materialization_failed` rejection and
|
|
451
|
+
the transaction leaves the prior active revision unchanged.
|
|
452
|
+
|
|
448
453
|
The first delivery is empty-history safe: Chapter checks a bounded aggregate
|
|
449
454
|
count before asking odla-db to order revision history. A freshly provisioned
|
|
450
455
|
follower therefore acknowledges revision 1 immediately instead of depending on
|
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
CHAPTER_PROMOTION_ADAPTER: () => CHAPTER_PROMOTION_ADAPTER,
|
|
23
24
|
DEFAULT_CHAPTER_COPY: () => DEFAULT_CHAPTER_COPY,
|
|
24
25
|
DEFAULT_SHARE_FIELDS: () => DEFAULT_SHARE_FIELDS,
|
|
25
26
|
MEMBERSHIP_PAGE_RENDERER: () => MEMBERSHIP_PAGE_RENDERER,
|
|
@@ -61,6 +62,7 @@ __export(index_exports, {
|
|
|
61
62
|
defineChapter: () => defineChapter,
|
|
62
63
|
emailGroupFrom: () => emailGroupFrom,
|
|
63
64
|
endForSlot: () => endForSlot,
|
|
65
|
+
exportChapterPromotion: () => exportChapterPromotion,
|
|
64
66
|
findApplicationRef: () => findApplicationRef,
|
|
65
67
|
findTier: () => findTier,
|
|
66
68
|
firstPaymentPatch: () => firstPaymentPatch,
|
|
@@ -3200,4 +3202,95 @@ function membershipTierPresentationFromMarkdown(presentation, source) {
|
|
|
3200
3202
|
if (!result.ok) throw new TypeError(`Invalid membership Markdown: ${result.errors.join("; ")}`);
|
|
3201
3203
|
return result.value;
|
|
3202
3204
|
}
|
|
3205
|
+
|
|
3206
|
+
// src/promotion.ts
|
|
3207
|
+
var import_promotion = require("@odla-ai/promotion");
|
|
3208
|
+
var CHAPTER_PROMOTION_ADAPTER = "@odla-ai/chapter/v1";
|
|
3209
|
+
var exclusions = (chapterId, paidTierIds) => [
|
|
3210
|
+
{
|
|
3211
|
+
kind: "chapter.providers",
|
|
3212
|
+
id: chapterId,
|
|
3213
|
+
reason: "provider_identity",
|
|
3214
|
+
paths: [
|
|
3215
|
+
...paidTierIds.map((id2) => `tiers[${id2}].stripePriceId`),
|
|
3216
|
+
"groups.stripePublishableKey",
|
|
3217
|
+
"applications.stripeCustomerId",
|
|
3218
|
+
"applications.stripeSubscriptionId",
|
|
3219
|
+
"meetings.googleEventId"
|
|
3220
|
+
],
|
|
3221
|
+
detail: "Stripe, Clerk, and Google identities are resolved independently in each target environment."
|
|
3222
|
+
},
|
|
3223
|
+
{
|
|
3224
|
+
kind: "chapter.runtime",
|
|
3225
|
+
id: chapterId,
|
|
3226
|
+
reason: "runtime_state",
|
|
3227
|
+
paths: ["applications.*", "meetings.*", "emailLog.*", "crm_*.*"],
|
|
3228
|
+
detail: "Applicants, meetings, messages, and CRM rows are operational state, not managed signup content."
|
|
3229
|
+
},
|
|
3230
|
+
{
|
|
3231
|
+
kind: "chapter.access",
|
|
3232
|
+
id: chapterId,
|
|
3233
|
+
reason: "personal_data",
|
|
3234
|
+
paths: ["admins.*", "superAdmins.*", "networkNotes.*"],
|
|
3235
|
+
detail: "People, access lists, and private network notes remain local to the target environment."
|
|
3236
|
+
},
|
|
3237
|
+
{
|
|
3238
|
+
kind: "chapter.history",
|
|
3239
|
+
id: chapterId,
|
|
3240
|
+
reason: "authority_history",
|
|
3241
|
+
paths: ["signupControls[active=false]", "signupControls.*At", "signupControls.environment"],
|
|
3242
|
+
detail: "The source retains immutable delivery history; only selected published content is exported."
|
|
3243
|
+
}
|
|
3244
|
+
];
|
|
3245
|
+
async function exportChapterPromotion(input) {
|
|
3246
|
+
if (!/^sha256:[0-9a-f]{64}$/.test(input.digest)) throw new TypeError("chapter promotion digest is invalid");
|
|
3247
|
+
const checked = validateSignupControlDocument(input.document);
|
|
3248
|
+
if (!checked.ok) throw new TypeError(checked.errors.join("; "));
|
|
3249
|
+
const document = checked.value;
|
|
3250
|
+
if (await signupControlDigest(document) !== input.digest) throw new TypeError("chapter promotion digest does not match its document");
|
|
3251
|
+
const revision = `chapter:${document.target.chapterId}:${document.revision}`;
|
|
3252
|
+
const promotionProvenance = {
|
|
3253
|
+
adapter: CHAPTER_PROMOTION_ADAPTER,
|
|
3254
|
+
sourceIds: [`signup-control:${document.revision}`, document.source.appId, document.target.chapterId].sort(),
|
|
3255
|
+
receiptDigests: [input.digest]
|
|
3256
|
+
};
|
|
3257
|
+
const artifact = (kind, id2, content) => ({
|
|
3258
|
+
kind,
|
|
3259
|
+
id: id2,
|
|
3260
|
+
sourceRevision: revision,
|
|
3261
|
+
provenance: promotionProvenance,
|
|
3262
|
+
content: (0, import_promotion.canonicalPromotionValue)(content)
|
|
3263
|
+
});
|
|
3264
|
+
const chapterId = document.target.chapterId;
|
|
3265
|
+
const artifacts = [
|
|
3266
|
+
artifact("chapter.catalog", chapterId, {
|
|
3267
|
+
chapterId,
|
|
3268
|
+
tiers: document.tiers.map(({ stripePriceId: _providerId, ...tier }) => tier)
|
|
3269
|
+
}),
|
|
3270
|
+
artifact("chapter.membership-page", chapterId, document.membershipPage),
|
|
3271
|
+
...document.application ? [artifact("chapter.application", chapterId, document.application)] : [],
|
|
3272
|
+
...document.policy ? [artifact("chapter.policy", chapterId, document.policy)] : [],
|
|
3273
|
+
...document.scheduling ? [artifact("chapter.scheduling", chapterId, document.scheduling)] : [],
|
|
3274
|
+
...document.theme ? [artifact("chapter.theme", chapterId, document.theme)] : []
|
|
3275
|
+
];
|
|
3276
|
+
return {
|
|
3277
|
+
adapter: CHAPTER_PROMOTION_ADAPTER,
|
|
3278
|
+
artifacts,
|
|
3279
|
+
exclusions: exclusions(chapterId, document.tiers.filter((tier) => tier.stripePriceId).map((tier) => tier.id)),
|
|
3280
|
+
preconditions: [
|
|
3281
|
+
{
|
|
3282
|
+
code: "chapter.signup-control.schema",
|
|
3283
|
+
path: "services.chapter.signupControl.schemaVersion",
|
|
3284
|
+
expected: document.schemaVersion,
|
|
3285
|
+
detail: "The target must support this Chapter signup-control document version."
|
|
3286
|
+
},
|
|
3287
|
+
{
|
|
3288
|
+
code: "chapter.identity",
|
|
3289
|
+
path: "app.appId",
|
|
3290
|
+
expected: chapterId,
|
|
3291
|
+
detail: "Chapter content can only target the chapter named by the signed source revision."
|
|
3292
|
+
}
|
|
3293
|
+
]
|
|
3294
|
+
};
|
|
3295
|
+
}
|
|
3203
3296
|
//# sourceMappingURL=index.cjs.map
|