@odla-ai/chapter 0.15.0 → 0.16.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.
@@ -221,18 +221,59 @@ interface ChapterConfig {
221
221
  auth?: ChapterAuth;
222
222
  /** odla services (db implied). Default `["db","calendar","o11y"]`. */
223
223
  services?: readonly string[];
224
- /** Apply-time account provisioning: `"invite"` (default) mints a Clerk
225
- * invitation, `"create"` makes the account server-side (so join can say the
226
- * account is ready), `"none"` skips it. Any of these needs a `clerk_secret_key`
227
- * vault secret to act. */
224
+ /** Apply-time account provisioning. **Default `"none"`** it provisions
225
+ * nothing, because the alternatives have an outbound side effect and a site
226
+ * that never made the choice must not be mailing people. `"create"` makes the
227
+ * Clerk account server-side (so join can say the account is ready);
228
+ * `"invite"` **emails the applicant a Clerk invitation**. Both non-default
229
+ * models need a `clerk_secret_key` vault secret to act. Opt in explicitly —
230
+ * leaving this unset provisions no accounts. */
228
231
  account?: AccountModel;
229
232
  /** WHEN lifecycle email fires. Addressing and content live on the group row
230
233
  * (owner-editable at runtime); this is the trigger, which is a build-time
231
234
  * decision. See {@link ChapterSends}. */
232
235
  sends?: ChapterSends;
236
+ /** Site policy for admin operations (approve side effects, refund rules).
237
+ * See {@link ChapterOperations}. */
238
+ operations?: ChapterOperations;
233
239
  }
234
240
  /** Apply-time Clerk account provisioning model. */
235
241
  type AccountModel = "invite" | "create" | "none";
242
+ /** Site policy for admin OPERATIONS: the DECISIONS, where the mechanics stay
243
+ * package-owned. Same model as {@link ChapterSends} — a site declares the rule,
244
+ * chapter enforces it. Distinct from {@link ChapterPolicy}, which is member-facing
245
+ * copy. (The privilege-escalation rules are NOT here: they are package-enforced
246
+ * in `canChangeRole`, gated on `auth.superAdmins`, so a site cannot weaken them.) */
247
+ interface ChapterOperations {
248
+ /** What approving an application does. */
249
+ onApprove?: {
250
+ /** Role to promote the applicant to in Clerk. Defaults to the ladder rung
251
+ * directly below admin (e.g. `"member"`); `false` promotes nobody. */
252
+ promoteTo?: string | false;
253
+ /** Group email template to send on approve. Default `"onboardingInvite"`;
254
+ * `false` sends nothing. */
255
+ send?: string | false;
256
+ };
257
+ /** Refund rules. */
258
+ refund?: {
259
+ /** Application statuses a refund may be issued from. Default: any status. */
260
+ allowedFrom?: readonly string[];
261
+ /** Also cancel the Stripe subscription. Default `true`. */
262
+ cancelSubscription?: boolean;
263
+ };
264
+ }
265
+ /** The fully-resolved {@link ChapterOperations} carried on the {@link Chapter}. */
266
+ interface ResolvedOperations {
267
+ onApprove: {
268
+ promoteTo: string | false;
269
+ send: string | false;
270
+ };
271
+ /** `allowedFrom: null` means "any status". */
272
+ refund: {
273
+ allowedFrom: readonly string[] | null;
274
+ cancelSubscription: boolean;
275
+ };
276
+ }
236
277
  /** When the admin notification fires: on application `submit` (default), on the
237
278
  * first successful `payment`, or `never` (the site drives it itself). */
238
279
  type AdminNotificationTrigger = "submit" | "payment" | "never";
@@ -263,10 +304,12 @@ interface Chapter {
263
304
  schema: DbSchema;
264
305
  rules: DbRules;
265
306
  services: readonly string[];
266
- /** Resolved apply-time account provisioning model (default `"invite"`). */
307
+ /** Resolved apply-time account provisioning model (default `"none"`). */
267
308
  account: AccountModel;
268
309
  /** Resolved send policy — when each lifecycle email fires. */
269
310
  sends: ResolvedSends;
311
+ /** Resolved admin-operation policy (approve side effects, refund rules). */
312
+ operations: ResolvedOperations;
270
313
  /** The seed `groups` row derived from config (chapter mode), else `null`. */
271
314
  groupSeed(): Record<string, unknown> | null;
272
315
  }
@@ -221,18 +221,59 @@ interface ChapterConfig {
221
221
  auth?: ChapterAuth;
222
222
  /** odla services (db implied). Default `["db","calendar","o11y"]`. */
223
223
  services?: readonly string[];
224
- /** Apply-time account provisioning: `"invite"` (default) mints a Clerk
225
- * invitation, `"create"` makes the account server-side (so join can say the
226
- * account is ready), `"none"` skips it. Any of these needs a `clerk_secret_key`
227
- * vault secret to act. */
224
+ /** Apply-time account provisioning. **Default `"none"`** it provisions
225
+ * nothing, because the alternatives have an outbound side effect and a site
226
+ * that never made the choice must not be mailing people. `"create"` makes the
227
+ * Clerk account server-side (so join can say the account is ready);
228
+ * `"invite"` **emails the applicant a Clerk invitation**. Both non-default
229
+ * models need a `clerk_secret_key` vault secret to act. Opt in explicitly —
230
+ * leaving this unset provisions no accounts. */
228
231
  account?: AccountModel;
229
232
  /** WHEN lifecycle email fires. Addressing and content live on the group row
230
233
  * (owner-editable at runtime); this is the trigger, which is a build-time
231
234
  * decision. See {@link ChapterSends}. */
232
235
  sends?: ChapterSends;
236
+ /** Site policy for admin operations (approve side effects, refund rules).
237
+ * See {@link ChapterOperations}. */
238
+ operations?: ChapterOperations;
233
239
  }
234
240
  /** Apply-time Clerk account provisioning model. */
235
241
  type AccountModel = "invite" | "create" | "none";
242
+ /** Site policy for admin OPERATIONS: the DECISIONS, where the mechanics stay
243
+ * package-owned. Same model as {@link ChapterSends} — a site declares the rule,
244
+ * chapter enforces it. Distinct from {@link ChapterPolicy}, which is member-facing
245
+ * copy. (The privilege-escalation rules are NOT here: they are package-enforced
246
+ * in `canChangeRole`, gated on `auth.superAdmins`, so a site cannot weaken them.) */
247
+ interface ChapterOperations {
248
+ /** What approving an application does. */
249
+ onApprove?: {
250
+ /** Role to promote the applicant to in Clerk. Defaults to the ladder rung
251
+ * directly below admin (e.g. `"member"`); `false` promotes nobody. */
252
+ promoteTo?: string | false;
253
+ /** Group email template to send on approve. Default `"onboardingInvite"`;
254
+ * `false` sends nothing. */
255
+ send?: string | false;
256
+ };
257
+ /** Refund rules. */
258
+ refund?: {
259
+ /** Application statuses a refund may be issued from. Default: any status. */
260
+ allowedFrom?: readonly string[];
261
+ /** Also cancel the Stripe subscription. Default `true`. */
262
+ cancelSubscription?: boolean;
263
+ };
264
+ }
265
+ /** The fully-resolved {@link ChapterOperations} carried on the {@link Chapter}. */
266
+ interface ResolvedOperations {
267
+ onApprove: {
268
+ promoteTo: string | false;
269
+ send: string | false;
270
+ };
271
+ /** `allowedFrom: null` means "any status". */
272
+ refund: {
273
+ allowedFrom: readonly string[] | null;
274
+ cancelSubscription: boolean;
275
+ };
276
+ }
236
277
  /** When the admin notification fires: on application `submit` (default), on the
237
278
  * first successful `payment`, or `never` (the site drives it itself). */
238
279
  type AdminNotificationTrigger = "submit" | "payment" | "never";
@@ -263,10 +304,12 @@ interface Chapter {
263
304
  schema: DbSchema;
264
305
  rules: DbRules;
265
306
  services: readonly string[];
266
- /** Resolved apply-time account provisioning model (default `"invite"`). */
307
+ /** Resolved apply-time account provisioning model (default `"none"`). */
267
308
  account: AccountModel;
268
309
  /** Resolved send policy — when each lifecycle email fires. */
269
310
  sends: ResolvedSends;
311
+ /** Resolved admin-operation policy (approve side effects, refund rules). */
312
+ operations: ResolvedOperations;
270
313
  /** The seed `groups` row derived from config (chapter mode), else `null`. */
271
314
  groupSeed(): Record<string, unknown> | null;
272
315
  }