@nebutra/contracts 2.0.0 → 3.0.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @nebutra/contracts@2.0.0 build /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/commerce/contracts
2
+ > @nebutra/contracts@3.0.0 build /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/commerce/contracts
3
3
  > tsup
4
4
 
5
5
  CLI Building entry: src/admin.ts, src/billing.ts, src/events.ts, src/identity.ts, src/index.ts, src/notifications.ts, src/sleptons.ts
@@ -9,39 +9,39 @@
9
9
  CLI Target: es2022
10
10
  CLI Cleaning output folder
11
11
  ESM Build start
12
- ESM dist/admin.js 1.04 KB
12
+ ESM dist/admin.js 1.12 KB
13
13
  ESM dist/billing.js 332.00 B
14
14
  ESM dist/events.js 173.00 B
15
15
  ESM dist/identity.js 563.00 B
16
- ESM dist/index.js 4.36 KB
17
- ESM dist/chunk-ERZTZ3PW.js 8.13 KB
16
+ ESM dist/index.js 4.44 KB
17
+ ESM dist/chunk-G65TWQGE.js 8.52 KB
18
18
  ESM dist/chunk-NFJTVIKD.js 1.32 KB
19
19
  ESM dist/chunk-2NXI4PJM.js 565.00 B
20
20
  ESM dist/chunk-5JNQ2KAT.js 2.07 KB
21
21
  ESM dist/notifications.js 1.11 KB
22
- ESM dist/chunk-F4BR76CX.js 2.91 KB
23
22
  ESM dist/sleptons.js 1.40 KB
23
+ ESM dist/chunk-BX2ZIODN.js 2.88 KB
24
24
  ESM dist/chunk-PU65L2HQ.js 6.74 KB
25
25
  ESM dist/admin.js.map 71.00 B
26
26
  ESM dist/billing.js.map 71.00 B
27
27
  ESM dist/events.js.map 71.00 B
28
28
  ESM dist/identity.js.map 71.00 B
29
29
  ESM dist/index.js.map 71.00 B
30
- ESM dist/chunk-ERZTZ3PW.js.map 16.58 KB
30
+ ESM dist/chunk-G65TWQGE.js.map 18.03 KB
31
31
  ESM dist/chunk-NFJTVIKD.js.map 2.78 KB
32
32
  ESM dist/chunk-2NXI4PJM.js.map 1.16 KB
33
33
  ESM dist/chunk-5JNQ2KAT.js.map 4.47 KB
34
34
  ESM dist/notifications.js.map 71.00 B
35
- ESM dist/chunk-F4BR76CX.js.map 6.05 KB
36
35
  ESM dist/sleptons.js.map 71.00 B
36
+ ESM dist/chunk-BX2ZIODN.js.map 6.00 KB
37
37
  ESM dist/chunk-PU65L2HQ.js.map 14.02 KB
38
- ESM ⚡️ Build success in 94ms
38
+ ESM ⚡️ Build success in 96ms
39
39
  DTS Build start
40
- DTS ⚡️ Build success in 22232ms
41
- DTS dist/index.d.ts 3.15 KB
42
- DTS dist/admin.d.ts 14.76 KB
40
+ DTS ⚡️ Build success in 28456ms
41
+ DTS dist/index.d.ts 3.18 KB
42
+ DTS dist/admin.d.ts 15.67 KB
43
43
  DTS dist/billing.d.ts 2.11 KB
44
44
  DTS dist/events.d.ts 1020.00 B
45
45
  DTS dist/identity.d.ts 4.03 KB
46
- DTS dist/notifications.d.ts 6.09 KB
46
+ DTS dist/notifications.d.ts 6.02 KB
47
47
  DTS dist/sleptons.d.ts 21.11 KB
@@ -1,15 +1,15 @@
1
1
 
2
- > @nebutra/contracts@2.0.0 test /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/commerce/contracts
2
+ > @nebutra/contracts@3.0.0 test /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/commerce/contracts
3
3
  > vitest run
4
4
 
5
5
 
6
6
   RUN  v4.1.4 /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/commerce/contracts
7
7
 
8
- ✓ src/__tests__/admin.test.ts (5 tests) 91ms
9
- ✓ src/sleptons.test.ts (6 tests) 50ms
8
+ ✓ src/__tests__/admin.test.ts (5 tests) 110ms
9
+ ✓ src/sleptons.test.ts (6 tests) 136ms
10
10
 
11
11
   Test Files  2 passed (2)
12
12
   Tests  11 passed (11)
13
-  Start at  02:31:07
14
-  Duration  1.49s (transform 388ms, setup 0ms, import 1.34s, tests 141ms, environment 0ms)
13
+  Start at  08:50:36
14
+  Duration  1.77s (transform 700ms, setup 0ms, import 1.66s, tests 246ms, environment 0ms)
15
15
 
@@ -1,4 +1,4 @@
1
1
 
2
- > @nebutra/contracts@2.0.0 typecheck /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/commerce/contracts
2
+ > @nebutra/contracts@3.0.0 typecheck /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/commerce/contracts
3
3
  > tsc --noEmit
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @nebutra/contracts
2
2
 
3
+ ## 3.0.0
4
+
3
5
  ## 2.0.0
4
6
 
5
7
  ### Minor Changes
package/dist/admin.d.ts CHANGED
@@ -412,5 +412,22 @@ type AdminError = z.infer<typeof AdminErrorSchema>;
412
412
  declare function assertApplyAllowed(action: AdminAction, request: ActionRequest): AdminError | null;
413
413
  /** Resolve a contract path against the manifest origin. */
414
414
  declare function resolveContractUrl(manifest: Pick<AdminManifest, "origin">, path: string): string;
415
+ /**
416
+ * The HTTP status an admin error travels as.
417
+ *
418
+ * Cloudflare sits in front of every admin and product host, and it replaces an
419
+ * origin's `502` or `504` with its own branded HTML error page. The body we
420
+ * wrote — the code and the message the operator needs — is discarded before the
421
+ * browser sees it, so the console can only report `network · HTTP 502`. A
422
+ * contract endpoint therefore never answers with a gateway status: an upstream
423
+ * that failed is `503`, and a fault of our own is `500`. Both reach the client
424
+ * with their JSON envelope intact.
425
+ */
426
+ declare const ADMIN_ERROR_STATUS: Record<AdminError["error"]["code"], number>;
427
+ /**
428
+ * Narrow an arbitrary status to one that survives the CDN, preserving anything
429
+ * already safe. Use it when echoing an upstream contract call's status.
430
+ */
431
+ declare function cdnSafeStatus(status: number | undefined, fallback?: number): number;
415
432
 
416
- export { ADMIN_CONTRACT_VERSION, type ActionPlan, ActionPlanSchema, type ActionRequest, ActionRequestSchema, type ActionResult, ActionResultSchema, type AdminAction, AdminActionSchema, type AdminColumn, AdminColumnSchema, type AdminDomain, type AdminDomainId, AdminDomainIdSchema, AdminDomainSchema, type AdminError, AdminErrorSchema, type AdminManifest, AdminManifestSchema, type AdminPolicy, AdminPolicySchema, type AdminResource, AdminResourceSchema, type AdminSeverity, AdminSeveritySchema, type AdminSignal, AdminSignalSchema, type AdminStatus, AdminStatusSchema, PlanDiffEntrySchema, type ResourceList, ResourceListSchema, STAFF_ROLE_RANK, type SignalReading, SignalReadingSchema, type StaffRole, StaffRoleSchema, assertApplyAllowed, resolveContractUrl, roleAtLeast };
433
+ export { ADMIN_CONTRACT_VERSION, ADMIN_ERROR_STATUS, type ActionPlan, ActionPlanSchema, type ActionRequest, ActionRequestSchema, type ActionResult, ActionResultSchema, type AdminAction, AdminActionSchema, type AdminColumn, AdminColumnSchema, type AdminDomain, type AdminDomainId, AdminDomainIdSchema, AdminDomainSchema, type AdminError, AdminErrorSchema, type AdminManifest, AdminManifestSchema, type AdminPolicy, AdminPolicySchema, type AdminResource, AdminResourceSchema, type AdminSeverity, AdminSeveritySchema, type AdminSignal, AdminSignalSchema, type AdminStatus, AdminStatusSchema, PlanDiffEntrySchema, type ResourceList, ResourceListSchema, STAFF_ROLE_RANK, type SignalReading, SignalReadingSchema, type StaffRole, StaffRoleSchema, assertApplyAllowed, cdnSafeStatus, resolveContractUrl, roleAtLeast };
package/dist/admin.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ADMIN_CONTRACT_VERSION,
3
+ ADMIN_ERROR_STATUS,
3
4
  ActionPlanSchema,
4
5
  ActionRequestSchema,
5
6
  ActionResultSchema,
@@ -20,11 +21,13 @@ import {
20
21
  SignalReadingSchema,
21
22
  StaffRoleSchema,
22
23
  assertApplyAllowed,
24
+ cdnSafeStatus,
23
25
  resolveContractUrl,
24
26
  roleAtLeast
25
- } from "./chunk-ERZTZ3PW.js";
27
+ } from "./chunk-G65TWQGE.js";
26
28
  export {
27
29
  ADMIN_CONTRACT_VERSION,
30
+ ADMIN_ERROR_STATUS,
28
31
  ActionPlanSchema,
29
32
  ActionRequestSchema,
30
33
  ActionResultSchema,
@@ -45,6 +48,7 @@ export {
45
48
  SignalReadingSchema,
46
49
  StaffRoleSchema,
47
50
  assertApplyAllowed,
51
+ cdnSafeStatus,
48
52
  resolveContractUrl,
49
53
  roleAtLeast
50
54
  };
@@ -8,9 +8,9 @@ var NotificationFrequencyContractSchema = z.enum([
8
8
  "never"
9
9
  ]);
10
10
  var NotificationRuntimeStatusContractSchema = z.object({
11
- provider: z.enum(["novu", "direct"]),
11
+ provider: z.enum(["direct"]),
12
12
  providerLabel: z.string().min(1),
13
- mode: z.enum(["managed", "self_hosted", "preview", "degraded"]),
13
+ mode: z.enum(["self_hosted", "preview"]),
14
14
  canManagePreferences: z.boolean(),
15
15
  canViewInbox: z.boolean(),
16
16
  canMarkInboxRead: z.boolean(),
@@ -82,4 +82,4 @@ export {
82
82
  NotificationSettingsUpdateRequestContractSchema,
83
83
  NotificationSettingsUpdateResponseContractSchema
84
84
  };
85
- //# sourceMappingURL=chunk-F4BR76CX.js.map
85
+ //# sourceMappingURL=chunk-BX2ZIODN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/notifications.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const NotificationChannelContractSchema = z.enum([\"in_app\", \"email\", \"push\", \"sms\", \"chat\"]);\nexport type NotificationChannelContract = z.infer<typeof NotificationChannelContractSchema>;\n\nexport const NotificationFrequencyContractSchema = z.enum([\n \"immediate\",\n \"daily\",\n \"weekly\",\n \"never\",\n]);\nexport type NotificationFrequencyContract = z.infer<typeof NotificationFrequencyContractSchema>;\n\nexport const NotificationRuntimeStatusContractSchema = z.object({\n provider: z.enum([\"direct\"]),\n providerLabel: z.string().min(1),\n mode: z.enum([\"self_hosted\", \"preview\"]),\n canManagePreferences: z.boolean(),\n canViewInbox: z.boolean(),\n canMarkInboxRead: z.boolean(),\n summary: z.string().min(1),\n reason: z.string().optional(),\n missing: z.array(z.string()),\n});\nexport type NotificationRuntimeStatusContract = z.infer<\n typeof NotificationRuntimeStatusContractSchema\n>;\n\nexport const NotificationPreferenceContractSchema = z.object({\n userId: z.string().min(1),\n tenantId: z.string().min(1).optional(),\n channel: NotificationChannelContractSchema,\n enabled: z.boolean(),\n disabledCategories: z.array(z.string()).optional(),\n frequency: NotificationFrequencyContractSchema,\n updatedAt: z.string().datetime().optional(),\n});\nexport type NotificationPreferenceContract = z.infer<typeof NotificationPreferenceContractSchema>;\n\nexport const NotificationItemContractSchema = z.object({\n id: z.string().min(1),\n userId: z.string().min(1),\n tenantId: z.string().min(1).optional(),\n type: z.string().min(1),\n title: z.string(),\n body: z.string(),\n data: z.record(z.string(), z.unknown()).optional(),\n read: z.boolean(),\n createdAt: z.string().datetime(),\n updatedAt: z.string().datetime(),\n});\nexport type NotificationItemContract = z.infer<typeof NotificationItemContractSchema>;\n\nexport const NotificationListQueryContractSchema = z.object({\n limit: z.coerce.number().int().min(1).max(100).default(50),\n offset: z.coerce.number().int().min(0).default(0),\n unreadOnly: z.coerce.boolean().optional(),\n});\nexport type NotificationListQueryContract = z.infer<typeof NotificationListQueryContractSchema>;\n\nexport const NotificationListResponseContractSchema = z.object({\n items: z.array(NotificationItemContractSchema),\n total: z.number().int().nonnegative(),\n unreadCount: z.number().int().nonnegative(),\n});\nexport type NotificationListResponseContract = z.infer<\n typeof NotificationListResponseContractSchema\n>;\n\nexport const NotificationUnreadCountResponseContractSchema = z.object({\n count: z.number().int().nonnegative(),\n});\nexport type NotificationUnreadCountResponseContract = z.infer<\n typeof NotificationUnreadCountResponseContractSchema\n>;\n\nexport const NotificationMarkReadRequestContractSchema = z.object({\n ids: z.array(z.string().min(1)).min(1).max(100),\n});\nexport type NotificationMarkReadRequestContract = z.infer<\n typeof NotificationMarkReadRequestContractSchema\n>;\n\nexport const NotificationMutationCountResponseContractSchema = z.object({\n count: z.number().int().nonnegative(),\n});\nexport type NotificationMutationCountResponseContract = z.infer<\n typeof NotificationMutationCountResponseContractSchema\n>;\n\nexport const NotificationSettingsUpdateRequestContractSchema = z.object({\n type: z.string().min(1),\n channel: NotificationChannelContractSchema,\n enabled: z.boolean(),\n});\nexport type NotificationSettingsUpdateRequestContract = z.infer<\n typeof NotificationSettingsUpdateRequestContractSchema\n>;\n\nexport const NotificationSettingsUpdateResponseContractSchema = z.object({\n ok: z.literal(true),\n preference: NotificationPreferenceContractSchema,\n});\nexport type NotificationSettingsUpdateResponseContract = z.infer<\n typeof NotificationSettingsUpdateResponseContractSchema\n>;\n"],"mappings":"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","names":[]}
@@ -228,6 +228,20 @@ function assertApplyAllowed(action, request) {
228
228
  function resolveContractUrl(manifest, path) {
229
229
  return new URL(path, manifest.origin).toString();
230
230
  }
231
+ var ADMIN_ERROR_STATUS = {
232
+ unauthenticated: 401,
233
+ forbidden: 403,
234
+ not_found: 404,
235
+ invalid_input: 400,
236
+ plan_required: 409,
237
+ plan_expired: 409,
238
+ upstream_unavailable: 503,
239
+ internal: 500
240
+ };
241
+ function cdnSafeStatus(status, fallback = 503) {
242
+ if (!status || status === 502 || status === 504 || status < 400 || status > 599) return fallback;
243
+ return status;
244
+ }
231
245
 
232
246
  export {
233
247
  ADMIN_CONTRACT_VERSION,
@@ -252,6 +266,8 @@ export {
252
266
  SignalReadingSchema,
253
267
  AdminErrorSchema,
254
268
  assertApplyAllowed,
255
- resolveContractUrl
269
+ resolveContractUrl,
270
+ ADMIN_ERROR_STATUS,
271
+ cdnSafeStatus
256
272
  };
257
- //# sourceMappingURL=chunk-ERZTZ3PW.js.map
273
+ //# sourceMappingURL=chunk-G65TWQGE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/admin.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Admin Contract — `nebutra.admin/v1`.\n *\n * Every Nebutra SaaS exposes one manifest describing the admin surface it\n * owns: resources (nouns), actions (audited verbs, plan → apply), signals\n * (probed facts) and policies (actions the system runs by itself). The\n * platform admin renders any product from its manifest; an agent derives\n * tools from it. Nothing product-specific lives in the renderer.\n *\n * See docs/plans/2026-09-08-admin-of-admins-model.md.\n */\n\nexport const ADMIN_CONTRACT_VERSION = \"nebutra.admin/v1\" as const;\n\n/** One status vocabulary. `unknown` is first-class and never renders green. */\nexport const AdminStatusSchema = z.enum([\"healthy\", \"degraded\", \"down\", \"unknown\"]);\nexport type AdminStatus = z.infer<typeof AdminStatusSchema>;\n\n/** One role ladder; product roles map onto it, staff grants mean the same everywhere. */\nexport const StaffRoleSchema = z.enum([\n \"platform_readonly\",\n \"platform_support\",\n \"platform_operator\",\n \"platform_owner\",\n]);\nexport type StaffRole = z.infer<typeof StaffRoleSchema>;\nexport const STAFF_ROLE_RANK: Record<StaffRole, number> = {\n platform_readonly: 0,\n platform_support: 1,\n platform_operator: 2,\n platform_owner: 3,\n};\nexport function roleAtLeast(role: StaffRole, required: StaffRole): boolean {\n return STAFF_ROLE_RANK[role] >= STAFF_ROLE_RANK[required];\n}\n\nexport const AdminSeveritySchema = z.enum([\"info\", \"warn\", \"critical\"]);\nexport type AdminSeverity = z.infer<typeof AdminSeveritySchema>;\n\n/** The canonical eleven. A product declares the subset it has. */\nexport const AdminDomainIdSchema = z.enum([\n \"identity\",\n \"access\",\n \"commerce\",\n \"usage\",\n \"catalog\",\n \"operations\",\n \"integrations\",\n \"trust\",\n \"support\",\n \"growth\",\n \"settings\",\n // Platform-only cross-cutting domain: shared AI supply (router).\n \"supply\",\n]);\nexport type AdminDomainId = z.infer<typeof AdminDomainIdSchema>;\n\nconst IdSchema = z\n .string()\n .min(1)\n .max(64)\n .regex(/^[a-z][a-z0-9._-]*$/, \"ids are lowercase dotted identifiers\");\nconst UrlPathSchema = z.string().min(1).regex(/^\\//, \"contract urls are origin-relative paths\");\n\nexport const AdminColumnSchema = z.object({\n key: z.string().min(1),\n label: z.string().min(1),\n kind: z.enum([\"text\", \"mono\", \"status\", \"badge\", \"number\", \"time\", \"link\"]).default(\"text\"),\n /** Right-align numbers; the renderer does not guess from values. */\n align: z.enum([\"start\", \"end\"]).default(\"start\"),\n});\nexport type AdminColumn = z.infer<typeof AdminColumnSchema>;\n\nexport const AdminResourceSchema = z.object({\n id: IdSchema,\n label: z.string().min(1),\n /** `GET list` → ResourceList */\n list: UrlPathSchema,\n /** `GET detail` with `{id}` placeholder → one item */\n detail: UrlPathSchema.optional(),\n columns: z.array(AdminColumnSchema).min(1),\n /** Column key that identifies a row. */\n key: z.string().min(1).default(\"id\"),\n search: z.boolean().default(false),\n /** Action ids applicable per row. */\n actions: z.array(IdSchema).default([]),\n});\nexport type AdminResource = z.infer<typeof AdminResourceSchema>;\n\nexport const AdminActionSchema = z.object({\n id: IdSchema,\n verb: z.string().min(1),\n /** Resource the action belongs to; omitted = domain-level action. */\n resource: IdSchema.optional(),\n /** Minimum staff role. Read-only tier never sees write controls. */\n role: StaffRoleSchema,\n /** `POST url` with ActionRequest (`mode: plan | apply`). */\n url: UrlPathSchema,\n /** Plan step is mandatory; `false` only for idempotent, non-destructive refreshes. */\n plan: z.boolean().default(true),\n destructive: z.boolean().default(false),\n /** JSON Schema for `input`; doubles as the MCP tool inputSchema. */\n input: z.record(z.string(), z.unknown()).optional(),\n description: z.string().optional(),\n});\nexport type AdminAction = z.infer<typeof AdminActionSchema>;\n\nexport const AdminSignalSchema = z.object({\n id: IdSchema,\n label: z.string().min(1),\n severity: AdminSeveritySchema,\n /** `GET probe` → SignalReading. Probed, never configured. */\n probe: UrlPathSchema,\n resource: IdSchema.optional(),\n /** Action that resolves the signal when raised. */\n action: IdSchema.optional(),\n});\nexport type AdminSignal = z.infer<typeof AdminSignalSchema>;\n\nexport const AdminPolicySchema = z.object({\n id: IdSchema,\n label: z.string().min(1),\n /** Event name (`nebutra/<domain>.<thing>.<verb>`) that triggers the policy. */\n on: z.string().min(1),\n runs: IdSchema,\n enabled: z.boolean().default(true),\n /** Natural-language intent the policy was compiled from, when it was. */\n intent: z.string().optional(),\n});\nexport type AdminPolicy = z.infer<typeof AdminPolicySchema>;\n\nexport const AdminDomainSchema = z.object({\n id: AdminDomainIdSchema,\n label: z.string().min(1),\n resources: z.array(AdminResourceSchema).default([]),\n actions: z.array(AdminActionSchema).default([]),\n signals: z.array(AdminSignalSchema).default([]),\n policies: z.array(AdminPolicySchema).default([]),\n /** Product-owned browser surface for what the generic renderer cannot express. */\n slot: UrlPathSchema.optional(),\n});\nexport type AdminDomain = z.infer<typeof AdminDomainSchema>;\n\nexport const AdminManifestSchema = z\n .object({\n contract: z.literal(ADMIN_CONTRACT_VERSION),\n product: IdSchema,\n label: z.string().min(1),\n version: z.string().min(1),\n /** Absolute origin every relative url resolves against. */\n origin: z.string().url(),\n graph: z.enum([\"core\", \"runtime\", \"labs\"]),\n status: z.enum([\"stable\", \"foundation\", \"wip\", \"experimental\"]),\n /** `GET health` → @nebutra/health HealthCheckResult. */\n health: UrlPathSchema,\n /** `GET audit?…` → audit events (nebutra.audit/v1). */\n audit: UrlPathSchema.optional(),\n domains: z.array(AdminDomainSchema).min(1),\n })\n .superRefine((m, ctx) => {\n for (const d of m.domains) {\n const actionIds = new Set(d.actions.map((a) => a.id));\n const resourceIds = new Set(d.resources.map((r) => r.id));\n for (const r of d.resources) {\n for (const a of r.actions) {\n if (!actionIds.has(a)) {\n ctx.addIssue({\n code: \"custom\",\n message: `resource ${r.id} references unknown action ${a}`,\n });\n }\n }\n }\n for (const s of d.signals) {\n if (s.action && !actionIds.has(s.action)) {\n ctx.addIssue({\n code: \"custom\",\n message: `signal ${s.id} references unknown action ${s.action}`,\n });\n }\n if (s.resource && !resourceIds.has(s.resource)) {\n ctx.addIssue({\n code: \"custom\",\n message: `signal ${s.id} references unknown resource ${s.resource}`,\n });\n }\n }\n for (const p of d.policies) {\n if (!actionIds.has(p.runs)) {\n ctx.addIssue({ code: \"custom\", message: `policy ${p.id} runs unknown action ${p.runs}` });\n }\n }\n }\n });\nexport type AdminManifest = z.infer<typeof AdminManifestSchema>;\n\n// -----------------------------------------------------------------------------\n// Wire envelopes\n// -----------------------------------------------------------------------------\n\nexport const ResourceListSchema = z.object({\n items: z.array(z.record(z.string(), z.unknown())),\n total: z.number().int().min(0),\n /** When the list was produced from live probes; omitted for pure reads. */\n probedAt: z.string().datetime().optional(),\n});\nexport type ResourceList = z.infer<typeof ResourceListSchema>;\n\nexport const ActionRequestSchema = z.discriminatedUnion(\"mode\", [\n z.object({ mode: z.literal(\"plan\"), input: z.record(z.string(), z.unknown()).default({}) }),\n z.object({\n mode: z.literal(\"apply\"),\n input: z.record(z.string(), z.unknown()).default({}),\n /** Required when the action is destructive; ties the apply to a reviewed plan. */\n planId: z.string().min(1).optional(),\n }),\n]);\nexport type ActionRequest = z.infer<typeof ActionRequestSchema>;\n\nexport const PlanDiffEntrySchema = z.object({\n op: z.enum([\"add\", \"remove\", \"change\"]),\n path: z.string().min(1),\n from: z.unknown().optional(),\n to: z.unknown().optional(),\n});\nexport const ActionPlanSchema = z.object({\n planId: z.string().min(1),\n summary: z.string().min(1),\n diff: z.array(PlanDiffEntrySchema),\n affected: z\n .array(z.object({ resource: IdSchema, id: z.string(), label: z.string().optional() }))\n .default([]),\n warnings: z.array(z.string()).default([]),\n /** Plans expire; an apply after this is refused. */\n expiresAt: z.string().datetime(),\n});\nexport type ActionPlan = z.infer<typeof ActionPlanSchema>;\n\nexport const ActionResultSchema = z.object({\n /** Audit event id written by the product for this apply. */\n auditId: z.string().min(1),\n summary: z.string().min(1),\n result: z.record(z.string(), z.unknown()).optional(),\n});\nexport type ActionResult = z.infer<typeof ActionResultSchema>;\n\nexport const SignalReadingSchema = z.object({\n id: IdSchema,\n status: z.enum([\"ok\", \"raised\", \"unknown\"]),\n severity: AdminSeveritySchema,\n probedAt: z.string().datetime(),\n title: z.string().optional(),\n detail: z.string().optional(),\n resource: IdSchema.optional(),\n action: IdSchema.optional(),\n data: z.record(z.string(), z.unknown()).optional(),\n});\nexport type SignalReading = z.infer<typeof SignalReadingSchema>;\n\n/** Standard error body for contract endpoints. */\nexport const AdminErrorSchema = z.object({\n error: z.object({\n code: z.enum([\n \"unauthenticated\",\n \"forbidden\",\n \"not_found\",\n \"invalid_input\",\n \"plan_required\",\n \"plan_expired\",\n \"upstream_unavailable\",\n \"internal\",\n ]),\n message: z.string(),\n }),\n});\nexport type AdminError = z.infer<typeof AdminErrorSchema>;\n\n/** Validate an apply against its action: destructive applies must reference a plan. */\nexport function assertApplyAllowed(action: AdminAction, request: ActionRequest): AdminError | null {\n if (request.mode !== \"apply\") return null;\n if ((action.destructive || action.plan) && !request.planId) {\n return {\n error: {\n code: \"plan_required\",\n message: `${action.id} requires a reviewed plan before apply`,\n },\n };\n }\n return null;\n}\n\n/** Resolve a contract path against the manifest origin. */\nexport function resolveContractUrl(manifest: Pick<AdminManifest, \"origin\">, path: string): string {\n return new URL(path, manifest.origin).toString();\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/admin.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Admin Contract — `nebutra.admin/v1`.\n *\n * Every Nebutra SaaS exposes one manifest describing the admin surface it\n * owns: resources (nouns), actions (audited verbs, plan → apply), signals\n * (probed facts) and policies (actions the system runs by itself). The\n * platform admin renders any product from its manifest; an agent derives\n * tools from it. Nothing product-specific lives in the renderer.\n *\n * See docs/plans/2026-09-08-admin-of-admins-model.md.\n */\n\nexport const ADMIN_CONTRACT_VERSION = \"nebutra.admin/v1\" as const;\n\n/** One status vocabulary. `unknown` is first-class and never renders green. */\nexport const AdminStatusSchema = z.enum([\"healthy\", \"degraded\", \"down\", \"unknown\"]);\nexport type AdminStatus = z.infer<typeof AdminStatusSchema>;\n\n/** One role ladder; product roles map onto it, staff grants mean the same everywhere. */\nexport const StaffRoleSchema = z.enum([\n \"platform_readonly\",\n \"platform_support\",\n \"platform_operator\",\n \"platform_owner\",\n]);\nexport type StaffRole = z.infer<typeof StaffRoleSchema>;\nexport const STAFF_ROLE_RANK: Record<StaffRole, number> = {\n platform_readonly: 0,\n platform_support: 1,\n platform_operator: 2,\n platform_owner: 3,\n};\nexport function roleAtLeast(role: StaffRole, required: StaffRole): boolean {\n return STAFF_ROLE_RANK[role] >= STAFF_ROLE_RANK[required];\n}\n\nexport const AdminSeveritySchema = z.enum([\"info\", \"warn\", \"critical\"]);\nexport type AdminSeverity = z.infer<typeof AdminSeveritySchema>;\n\n/** The canonical eleven. A product declares the subset it has. */\nexport const AdminDomainIdSchema = z.enum([\n \"identity\",\n \"access\",\n \"commerce\",\n \"usage\",\n \"catalog\",\n \"operations\",\n \"integrations\",\n \"trust\",\n \"support\",\n \"growth\",\n \"settings\",\n // Platform-only cross-cutting domain: shared AI supply (router).\n \"supply\",\n]);\nexport type AdminDomainId = z.infer<typeof AdminDomainIdSchema>;\n\nconst IdSchema = z\n .string()\n .min(1)\n .max(64)\n .regex(/^[a-z][a-z0-9._-]*$/, \"ids are lowercase dotted identifiers\");\nconst UrlPathSchema = z.string().min(1).regex(/^\\//, \"contract urls are origin-relative paths\");\n\nexport const AdminColumnSchema = z.object({\n key: z.string().min(1),\n label: z.string().min(1),\n kind: z.enum([\"text\", \"mono\", \"status\", \"badge\", \"number\", \"time\", \"link\"]).default(\"text\"),\n /** Right-align numbers; the renderer does not guess from values. */\n align: z.enum([\"start\", \"end\"]).default(\"start\"),\n});\nexport type AdminColumn = z.infer<typeof AdminColumnSchema>;\n\nexport const AdminResourceSchema = z.object({\n id: IdSchema,\n label: z.string().min(1),\n /** `GET list` → ResourceList */\n list: UrlPathSchema,\n /** `GET detail` with `{id}` placeholder → one item */\n detail: UrlPathSchema.optional(),\n columns: z.array(AdminColumnSchema).min(1),\n /** Column key that identifies a row. */\n key: z.string().min(1).default(\"id\"),\n search: z.boolean().default(false),\n /** Action ids applicable per row. */\n actions: z.array(IdSchema).default([]),\n});\nexport type AdminResource = z.infer<typeof AdminResourceSchema>;\n\nexport const AdminActionSchema = z.object({\n id: IdSchema,\n verb: z.string().min(1),\n /** Resource the action belongs to; omitted = domain-level action. */\n resource: IdSchema.optional(),\n /** Minimum staff role. Read-only tier never sees write controls. */\n role: StaffRoleSchema,\n /** `POST url` with ActionRequest (`mode: plan | apply`). */\n url: UrlPathSchema,\n /** Plan step is mandatory; `false` only for idempotent, non-destructive refreshes. */\n plan: z.boolean().default(true),\n destructive: z.boolean().default(false),\n /** JSON Schema for `input`; doubles as the MCP tool inputSchema. */\n input: z.record(z.string(), z.unknown()).optional(),\n description: z.string().optional(),\n});\nexport type AdminAction = z.infer<typeof AdminActionSchema>;\n\nexport const AdminSignalSchema = z.object({\n id: IdSchema,\n label: z.string().min(1),\n severity: AdminSeveritySchema,\n /** `GET probe` → SignalReading. Probed, never configured. */\n probe: UrlPathSchema,\n resource: IdSchema.optional(),\n /** Action that resolves the signal when raised. */\n action: IdSchema.optional(),\n});\nexport type AdminSignal = z.infer<typeof AdminSignalSchema>;\n\nexport const AdminPolicySchema = z.object({\n id: IdSchema,\n label: z.string().min(1),\n /** Event name (`nebutra/<domain>.<thing>.<verb>`) that triggers the policy. */\n on: z.string().min(1),\n runs: IdSchema,\n enabled: z.boolean().default(true),\n /** Natural-language intent the policy was compiled from, when it was. */\n intent: z.string().optional(),\n});\nexport type AdminPolicy = z.infer<typeof AdminPolicySchema>;\n\nexport const AdminDomainSchema = z.object({\n id: AdminDomainIdSchema,\n label: z.string().min(1),\n resources: z.array(AdminResourceSchema).default([]),\n actions: z.array(AdminActionSchema).default([]),\n signals: z.array(AdminSignalSchema).default([]),\n policies: z.array(AdminPolicySchema).default([]),\n /** Product-owned browser surface for what the generic renderer cannot express. */\n slot: UrlPathSchema.optional(),\n});\nexport type AdminDomain = z.infer<typeof AdminDomainSchema>;\n\nexport const AdminManifestSchema = z\n .object({\n contract: z.literal(ADMIN_CONTRACT_VERSION),\n product: IdSchema,\n label: z.string().min(1),\n version: z.string().min(1),\n /** Absolute origin every relative url resolves against. */\n origin: z.string().url(),\n graph: z.enum([\"core\", \"runtime\", \"labs\"]),\n status: z.enum([\"stable\", \"foundation\", \"wip\", \"experimental\"]),\n /** `GET health` → @nebutra/health HealthCheckResult. */\n health: UrlPathSchema,\n /** `GET audit?…` → audit events (nebutra.audit/v1). */\n audit: UrlPathSchema.optional(),\n domains: z.array(AdminDomainSchema).min(1),\n })\n .superRefine((m, ctx) => {\n for (const d of m.domains) {\n const actionIds = new Set(d.actions.map((a) => a.id));\n const resourceIds = new Set(d.resources.map((r) => r.id));\n for (const r of d.resources) {\n for (const a of r.actions) {\n if (!actionIds.has(a)) {\n ctx.addIssue({\n code: \"custom\",\n message: `resource ${r.id} references unknown action ${a}`,\n });\n }\n }\n }\n for (const s of d.signals) {\n if (s.action && !actionIds.has(s.action)) {\n ctx.addIssue({\n code: \"custom\",\n message: `signal ${s.id} references unknown action ${s.action}`,\n });\n }\n if (s.resource && !resourceIds.has(s.resource)) {\n ctx.addIssue({\n code: \"custom\",\n message: `signal ${s.id} references unknown resource ${s.resource}`,\n });\n }\n }\n for (const p of d.policies) {\n if (!actionIds.has(p.runs)) {\n ctx.addIssue({ code: \"custom\", message: `policy ${p.id} runs unknown action ${p.runs}` });\n }\n }\n }\n });\nexport type AdminManifest = z.infer<typeof AdminManifestSchema>;\n\n// -----------------------------------------------------------------------------\n// Wire envelopes\n// -----------------------------------------------------------------------------\n\nexport const ResourceListSchema = z.object({\n items: z.array(z.record(z.string(), z.unknown())),\n total: z.number().int().min(0),\n /** When the list was produced from live probes; omitted for pure reads. */\n probedAt: z.string().datetime().optional(),\n});\nexport type ResourceList = z.infer<typeof ResourceListSchema>;\n\nexport const ActionRequestSchema = z.discriminatedUnion(\"mode\", [\n z.object({ mode: z.literal(\"plan\"), input: z.record(z.string(), z.unknown()).default({}) }),\n z.object({\n mode: z.literal(\"apply\"),\n input: z.record(z.string(), z.unknown()).default({}),\n /** Required when the action is destructive; ties the apply to a reviewed plan. */\n planId: z.string().min(1).optional(),\n }),\n]);\nexport type ActionRequest = z.infer<typeof ActionRequestSchema>;\n\nexport const PlanDiffEntrySchema = z.object({\n op: z.enum([\"add\", \"remove\", \"change\"]),\n path: z.string().min(1),\n from: z.unknown().optional(),\n to: z.unknown().optional(),\n});\nexport const ActionPlanSchema = z.object({\n planId: z.string().min(1),\n summary: z.string().min(1),\n diff: z.array(PlanDiffEntrySchema),\n affected: z\n .array(z.object({ resource: IdSchema, id: z.string(), label: z.string().optional() }))\n .default([]),\n warnings: z.array(z.string()).default([]),\n /** Plans expire; an apply after this is refused. */\n expiresAt: z.string().datetime(),\n});\nexport type ActionPlan = z.infer<typeof ActionPlanSchema>;\n\nexport const ActionResultSchema = z.object({\n /** Audit event id written by the product for this apply. */\n auditId: z.string().min(1),\n summary: z.string().min(1),\n result: z.record(z.string(), z.unknown()).optional(),\n});\nexport type ActionResult = z.infer<typeof ActionResultSchema>;\n\nexport const SignalReadingSchema = z.object({\n id: IdSchema,\n status: z.enum([\"ok\", \"raised\", \"unknown\"]),\n severity: AdminSeveritySchema,\n probedAt: z.string().datetime(),\n title: z.string().optional(),\n detail: z.string().optional(),\n resource: IdSchema.optional(),\n action: IdSchema.optional(),\n data: z.record(z.string(), z.unknown()).optional(),\n});\nexport type SignalReading = z.infer<typeof SignalReadingSchema>;\n\n/** Standard error body for contract endpoints. */\nexport const AdminErrorSchema = z.object({\n error: z.object({\n code: z.enum([\n \"unauthenticated\",\n \"forbidden\",\n \"not_found\",\n \"invalid_input\",\n \"plan_required\",\n \"plan_expired\",\n \"upstream_unavailable\",\n \"internal\",\n ]),\n message: z.string(),\n }),\n});\nexport type AdminError = z.infer<typeof AdminErrorSchema>;\n\n/** Validate an apply against its action: destructive applies must reference a plan. */\nexport function assertApplyAllowed(action: AdminAction, request: ActionRequest): AdminError | null {\n if (request.mode !== \"apply\") return null;\n if ((action.destructive || action.plan) && !request.planId) {\n return {\n error: {\n code: \"plan_required\",\n message: `${action.id} requires a reviewed plan before apply`,\n },\n };\n }\n return null;\n}\n\n/** Resolve a contract path against the manifest origin. */\nexport function resolveContractUrl(manifest: Pick<AdminManifest, \"origin\">, path: string): string {\n return new URL(path, manifest.origin).toString();\n}\n\n/**\n * The HTTP status an admin error travels as.\n *\n * Cloudflare sits in front of every admin and product host, and it replaces an\n * origin's `502` or `504` with its own branded HTML error page. The body we\n * wrote — the code and the message the operator needs — is discarded before the\n * browser sees it, so the console can only report `network · HTTP 502`. A\n * contract endpoint therefore never answers with a gateway status: an upstream\n * that failed is `503`, and a fault of our own is `500`. Both reach the client\n * with their JSON envelope intact.\n */\nexport const ADMIN_ERROR_STATUS: Record<AdminError[\"error\"][\"code\"], number> = {\n unauthenticated: 401,\n forbidden: 403,\n not_found: 404,\n invalid_input: 400,\n plan_required: 409,\n plan_expired: 409,\n upstream_unavailable: 503,\n internal: 500,\n};\n\n/**\n * Narrow an arbitrary status to one that survives the CDN, preserving anything\n * already safe. Use it when echoing an upstream contract call's status.\n */\nexport function cdnSafeStatus(status: number | undefined, fallback = 503): number {\n if (!status || status === 502 || status === 504 || status < 400 || status > 599) return fallback;\n return status;\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { ADMIN_CONTRACT_VERSION, ActionPlan, ActionPlanSchema, ActionRequest, ActionRequestSchema, ActionResult, ActionResultSchema, AdminAction, AdminActionSchema, AdminColumn, AdminColumnSchema, AdminDomain, AdminDomainId, AdminDomainIdSchema, AdminDomainSchema, AdminError, AdminErrorSchema, AdminManifest, AdminManifestSchema, AdminPolicy, AdminPolicySchema, AdminResource, AdminResourceSchema, AdminSeverity, AdminSeveritySchema, AdminSignal, AdminSignalSchema, AdminStatus, AdminStatusSchema, PlanDiffEntrySchema, ResourceList, ResourceListSchema, STAFF_ROLE_RANK, SignalReading, SignalReadingSchema, StaffRole, StaffRoleSchema, assertApplyAllowed, resolveContractUrl, roleAtLeast } from './admin.js';
1
+ export { ADMIN_CONTRACT_VERSION, ADMIN_ERROR_STATUS, ActionPlan, ActionPlanSchema, ActionRequest, ActionRequestSchema, ActionResult, ActionResultSchema, AdminAction, AdminActionSchema, AdminColumn, AdminColumnSchema, AdminDomain, AdminDomainId, AdminDomainIdSchema, AdminDomainSchema, AdminError, AdminErrorSchema, AdminManifest, AdminManifestSchema, AdminPolicy, AdminPolicySchema, AdminResource, AdminResourceSchema, AdminSeverity, AdminSeveritySchema, AdminSignal, AdminSignalSchema, AdminStatus, AdminStatusSchema, PlanDiffEntrySchema, ResourceList, ResourceListSchema, STAFF_ROLE_RANK, SignalReading, SignalReadingSchema, StaffRole, StaffRoleSchema, assertApplyAllowed, cdnSafeStatus, resolveContractUrl, roleAtLeast } from './admin.js';
2
2
  export { PricingCatalogVersion, PricingCatalogVersionSchema, UsageLedgerEntryInput, UsageLedgerEntryInputSchema, UsageLedgerSourceContract, UsageLedgerSourceContractSchema, UsageTypeContract, UsageTypeContractSchema } from './billing.js';
3
3
  export { EventContext, EventContextSchema, EventEnvelope, EventEnvelopeSchema } from './events.js';
4
4
  export { AuthProvider, AuthProviderSchema, CanonicalIdentity, CanonicalIdentitySchema, CanonicalPlan, CanonicalPlanSchema, CanonicalRole, CanonicalRoleSchema, ExternalAccountLink, ExternalAccountLinkSchema, NebutraOAuthScope, NebutraOAuthScopeSchema, OAuthClientRegistration, OAuthClientRegistrationSchema, OAuthClientType, OAuthClientTypeSchema, TenantHeaderContract, TenantHeaderContractSchema } from './identity.js';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ADMIN_CONTRACT_VERSION,
3
+ ADMIN_ERROR_STATUS,
3
4
  ActionPlanSchema,
4
5
  ActionRequestSchema,
5
6
  ActionResultSchema,
@@ -20,9 +21,10 @@ import {
20
21
  SignalReadingSchema,
21
22
  StaffRoleSchema,
22
23
  assertApplyAllowed,
24
+ cdnSafeStatus,
23
25
  resolveContractUrl,
24
26
  roleAtLeast
25
- } from "./chunk-ERZTZ3PW.js";
27
+ } from "./chunk-G65TWQGE.js";
26
28
  import {
27
29
  PricingCatalogVersionSchema,
28
30
  UsageLedgerEntryInputSchema,
@@ -57,7 +59,7 @@ import {
57
59
  NotificationSettingsUpdateRequestContractSchema,
58
60
  NotificationSettingsUpdateResponseContractSchema,
59
61
  NotificationUnreadCountResponseContractSchema
60
- } from "./chunk-F4BR76CX.js";
62
+ } from "./chunk-BX2ZIODN.js";
61
63
  import {
62
64
  DEFAULT_RESUME_MARGINS,
63
65
  ExperienceKindSchema,
@@ -90,6 +92,7 @@ import {
90
92
  } from "./chunk-PU65L2HQ.js";
91
93
  export {
92
94
  ADMIN_CONTRACT_VERSION,
95
+ ADMIN_ERROR_STATUS,
93
96
  ActionPlanSchema,
94
97
  ActionRequestSchema,
95
98
  ActionResultSchema,
@@ -165,6 +168,7 @@ export {
165
168
  UsageTypeContractSchema,
166
169
  VentureStageSchema,
167
170
  assertApplyAllowed,
171
+ cdnSafeStatus,
168
172
  resolveContractUrl,
169
173
  roleAtLeast
170
174
  };
@@ -17,13 +17,10 @@ declare const NotificationFrequencyContractSchema: z.ZodEnum<{
17
17
  type NotificationFrequencyContract = z.infer<typeof NotificationFrequencyContractSchema>;
18
18
  declare const NotificationRuntimeStatusContractSchema: z.ZodObject<{
19
19
  provider: z.ZodEnum<{
20
- novu: "novu";
21
20
  direct: "direct";
22
21
  }>;
23
22
  providerLabel: z.ZodString;
24
23
  mode: z.ZodEnum<{
25
- degraded: "degraded";
26
- managed: "managed";
27
24
  self_hosted: "self_hosted";
28
25
  preview: "preview";
29
26
  }>;
@@ -11,7 +11,7 @@ import {
11
11
  NotificationSettingsUpdateRequestContractSchema,
12
12
  NotificationSettingsUpdateResponseContractSchema,
13
13
  NotificationUnreadCountResponseContractSchema
14
- } from "./chunk-F4BR76CX.js";
14
+ } from "./chunk-BX2ZIODN.js";
15
15
  export {
16
16
  NotificationChannelContractSchema,
17
17
  NotificationFrequencyContractSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nebutra/contracts",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Canonical API/event/domain contracts for Nebutra superstarter",
5
5
  "private": false,
6
6
  "nebutra": {
package/src/admin.ts CHANGED
@@ -295,3 +295,34 @@ export function assertApplyAllowed(action: AdminAction, request: ActionRequest):
295
295
  export function resolveContractUrl(manifest: Pick<AdminManifest, "origin">, path: string): string {
296
296
  return new URL(path, manifest.origin).toString();
297
297
  }
298
+
299
+ /**
300
+ * The HTTP status an admin error travels as.
301
+ *
302
+ * Cloudflare sits in front of every admin and product host, and it replaces an
303
+ * origin's `502` or `504` with its own branded HTML error page. The body we
304
+ * wrote — the code and the message the operator needs — is discarded before the
305
+ * browser sees it, so the console can only report `network · HTTP 502`. A
306
+ * contract endpoint therefore never answers with a gateway status: an upstream
307
+ * that failed is `503`, and a fault of our own is `500`. Both reach the client
308
+ * with their JSON envelope intact.
309
+ */
310
+ export const ADMIN_ERROR_STATUS: Record<AdminError["error"]["code"], number> = {
311
+ unauthenticated: 401,
312
+ forbidden: 403,
313
+ not_found: 404,
314
+ invalid_input: 400,
315
+ plan_required: 409,
316
+ plan_expired: 409,
317
+ upstream_unavailable: 503,
318
+ internal: 500,
319
+ };
320
+
321
+ /**
322
+ * Narrow an arbitrary status to one that survives the CDN, preserving anything
323
+ * already safe. Use it when echoing an upstream contract call's status.
324
+ */
325
+ export function cdnSafeStatus(status: number | undefined, fallback = 503): number {
326
+ if (!status || status === 502 || status === 504 || status < 400 || status > 599) return fallback;
327
+ return status;
328
+ }
@@ -12,9 +12,9 @@ export const NotificationFrequencyContractSchema = z.enum([
12
12
  export type NotificationFrequencyContract = z.infer<typeof NotificationFrequencyContractSchema>;
13
13
 
14
14
  export const NotificationRuntimeStatusContractSchema = z.object({
15
- provider: z.enum(["novu", "direct"]),
15
+ provider: z.enum(["direct"]),
16
16
  providerLabel: z.string().min(1),
17
- mode: z.enum(["managed", "self_hosted", "preview", "degraded"]),
17
+ mode: z.enum(["self_hosted", "preview"]),
18
18
  canManagePreferences: z.boolean(),
19
19
  canViewInbox: z.boolean(),
20
20
  canMarkInboxRead: z.boolean(),
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/notifications.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const NotificationChannelContractSchema = z.enum([\"in_app\", \"email\", \"push\", \"sms\", \"chat\"]);\nexport type NotificationChannelContract = z.infer<typeof NotificationChannelContractSchema>;\n\nexport const NotificationFrequencyContractSchema = z.enum([\n \"immediate\",\n \"daily\",\n \"weekly\",\n \"never\",\n]);\nexport type NotificationFrequencyContract = z.infer<typeof NotificationFrequencyContractSchema>;\n\nexport const NotificationRuntimeStatusContractSchema = z.object({\n provider: z.enum([\"novu\", \"direct\"]),\n providerLabel: z.string().min(1),\n mode: z.enum([\"managed\", \"self_hosted\", \"preview\", \"degraded\"]),\n canManagePreferences: z.boolean(),\n canViewInbox: z.boolean(),\n canMarkInboxRead: z.boolean(),\n summary: z.string().min(1),\n reason: z.string().optional(),\n missing: z.array(z.string()),\n});\nexport type NotificationRuntimeStatusContract = z.infer<\n typeof NotificationRuntimeStatusContractSchema\n>;\n\nexport const NotificationPreferenceContractSchema = z.object({\n userId: z.string().min(1),\n tenantId: z.string().min(1).optional(),\n channel: NotificationChannelContractSchema,\n enabled: z.boolean(),\n disabledCategories: z.array(z.string()).optional(),\n frequency: NotificationFrequencyContractSchema,\n updatedAt: z.string().datetime().optional(),\n});\nexport type NotificationPreferenceContract = z.infer<typeof NotificationPreferenceContractSchema>;\n\nexport const NotificationItemContractSchema = z.object({\n id: z.string().min(1),\n userId: z.string().min(1),\n tenantId: z.string().min(1).optional(),\n type: z.string().min(1),\n title: z.string(),\n body: z.string(),\n data: z.record(z.string(), z.unknown()).optional(),\n read: z.boolean(),\n createdAt: z.string().datetime(),\n updatedAt: z.string().datetime(),\n});\nexport type NotificationItemContract = z.infer<typeof NotificationItemContractSchema>;\n\nexport const NotificationListQueryContractSchema = z.object({\n limit: z.coerce.number().int().min(1).max(100).default(50),\n offset: z.coerce.number().int().min(0).default(0),\n unreadOnly: z.coerce.boolean().optional(),\n});\nexport type NotificationListQueryContract = z.infer<typeof NotificationListQueryContractSchema>;\n\nexport const NotificationListResponseContractSchema = z.object({\n items: z.array(NotificationItemContractSchema),\n total: z.number().int().nonnegative(),\n unreadCount: z.number().int().nonnegative(),\n});\nexport type NotificationListResponseContract = z.infer<\n typeof NotificationListResponseContractSchema\n>;\n\nexport const NotificationUnreadCountResponseContractSchema = z.object({\n count: z.number().int().nonnegative(),\n});\nexport type NotificationUnreadCountResponseContract = z.infer<\n typeof NotificationUnreadCountResponseContractSchema\n>;\n\nexport const NotificationMarkReadRequestContractSchema = z.object({\n ids: z.array(z.string().min(1)).min(1).max(100),\n});\nexport type NotificationMarkReadRequestContract = z.infer<\n typeof NotificationMarkReadRequestContractSchema\n>;\n\nexport const NotificationMutationCountResponseContractSchema = z.object({\n count: z.number().int().nonnegative(),\n});\nexport type NotificationMutationCountResponseContract = z.infer<\n typeof NotificationMutationCountResponseContractSchema\n>;\n\nexport const NotificationSettingsUpdateRequestContractSchema = z.object({\n type: z.string().min(1),\n channel: NotificationChannelContractSchema,\n enabled: z.boolean(),\n});\nexport type NotificationSettingsUpdateRequestContract = z.infer<\n typeof NotificationSettingsUpdateRequestContractSchema\n>;\n\nexport const NotificationSettingsUpdateResponseContractSchema = z.object({\n ok: z.literal(true),\n preference: NotificationPreferenceContractSchema,\n});\nexport type NotificationSettingsUpdateResponseContract = z.infer<\n typeof NotificationSettingsUpdateResponseContractSchema\n>;\n"],"mappings":"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","names":[]}