@fayz-ai/core 0.10.0 → 0.12.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.
Files changed (112) hide show
  1. package/dist/chunk-7GJTLBG3.js +566 -0
  2. package/dist/chunk-7GJTLBG3.js.map +1 -0
  3. package/dist/chunk-ED6NBH6U.js +348 -0
  4. package/dist/chunk-ED6NBH6U.js.map +1 -0
  5. package/dist/chunk-EWKX4VUM.js +429 -0
  6. package/dist/chunk-EWKX4VUM.js.map +1 -0
  7. package/dist/chunk-IKZR3WSK.js +289 -0
  8. package/dist/chunk-IKZR3WSK.js.map +1 -0
  9. package/dist/chunk-KFBEKFII.js +320 -0
  10. package/dist/chunk-KFBEKFII.js.map +1 -0
  11. package/dist/{chunk-732GZEUI.js → chunk-RRYFXUQX.js} +22 -367
  12. package/dist/chunk-RRYFXUQX.js.map +1 -0
  13. package/dist/chunk-S5FOFKR4.js +1618 -0
  14. package/dist/chunk-S5FOFKR4.js.map +1 -0
  15. package/dist/{chunk-M27JPX3K.js → chunk-U3252GZO.js} +366 -24
  16. package/dist/chunk-U3252GZO.js.map +1 -0
  17. package/dist/connector-runtime/index.d.ts +15 -0
  18. package/dist/connector-runtime/index.d.ts.map +1 -0
  19. package/dist/connector-runtime/index.js +3 -0
  20. package/dist/connector-runtime/index.js.map +1 -0
  21. package/dist/data/archetype.d.ts.map +1 -1
  22. package/dist/data/bulk.d.ts +24 -0
  23. package/dist/data/bulk.d.ts.map +1 -1
  24. package/dist/data/cached.d.ts +5 -1
  25. package/dist/data/cached.d.ts.map +1 -1
  26. package/dist/data/custom-fields.d.ts +5 -0
  27. package/dist/data/custom-fields.d.ts.map +1 -0
  28. package/dist/data/errors.d.ts +44 -0
  29. package/dist/data/errors.d.ts.map +1 -0
  30. package/dist/data/index.d.ts +10 -1
  31. package/dist/data/index.d.ts.map +1 -1
  32. package/dist/data/index.js +3 -1
  33. package/dist/data/mock.d.ts.map +1 -1
  34. package/dist/data/offline.d.ts +45 -0
  35. package/dist/data/offline.d.ts.map +1 -0
  36. package/dist/data/platform-api.d.ts.map +1 -1
  37. package/dist/data/query.d.ts +91 -0
  38. package/dist/data/query.d.ts.map +1 -0
  39. package/dist/data/resolve.d.ts.map +1 -1
  40. package/dist/data/supabase.d.ts.map +1 -1
  41. package/dist/data/types.d.ts +21 -0
  42. package/dist/data/types.d.ts.map +1 -1
  43. package/dist/events/bus.d.ts +12 -0
  44. package/dist/events/bus.d.ts.map +1 -0
  45. package/dist/events/index.d.ts +3 -11
  46. package/dist/events/index.d.ts.map +1 -1
  47. package/dist/events/log.d.ts.map +1 -1
  48. package/dist/fields/store.d.ts +45 -0
  49. package/dist/fields/store.d.ts.map +1 -0
  50. package/dist/i18n/index.d.ts.map +1 -1
  51. package/dist/i18n/index.js +1 -1
  52. package/dist/i18n/shell-translations.en.d.ts.map +1 -1
  53. package/dist/i18n/shell-translations.pt-br.d.ts.map +1 -1
  54. package/dist/index.d.ts +35 -11
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +326 -252
  57. package/dist/index.js.map +1 -1
  58. package/dist/integrations/events.d.ts +7 -0
  59. package/dist/integrations/events.d.ts.map +1 -0
  60. package/dist/integrations/index.d.ts +663 -0
  61. package/dist/integrations/index.d.ts.map +1 -0
  62. package/dist/integrations/index.js +3 -1
  63. package/dist/integrations/permissions.d.ts +132 -0
  64. package/dist/integrations/permissions.d.ts.map +1 -0
  65. package/dist/integrations/request.d.ts +170 -0
  66. package/dist/integrations/request.d.ts.map +1 -0
  67. package/dist/integrations/runtime-token.d.ts +33 -0
  68. package/dist/integrations/runtime-token.d.ts.map +1 -0
  69. package/dist/integrations/runtime.d.ts +398 -0
  70. package/dist/integrations/runtime.d.ts.map +1 -0
  71. package/dist/integrations/settings.d.ts +102 -0
  72. package/dist/integrations/settings.d.ts.map +1 -0
  73. package/dist/integrations/store.d.ts +145 -0
  74. package/dist/integrations/store.d.ts.map +1 -0
  75. package/dist/lib/cache-idb.d.ts +54 -0
  76. package/dist/lib/cache-idb.d.ts.map +1 -0
  77. package/dist/lib/cache.d.ts +2 -0
  78. package/dist/lib/cache.d.ts.map +1 -1
  79. package/dist/plugin/index.js +2 -1
  80. package/dist/plugin/runtime.d.ts.map +1 -1
  81. package/dist/registry/entities.d.ts +41 -15
  82. package/dist/registry/entities.d.ts.map +1 -1
  83. package/dist/registry/index.d.ts +2 -2
  84. package/dist/registry/index.d.ts.map +1 -1
  85. package/dist/search/engine.d.ts.map +1 -1
  86. package/dist/search/types.d.ts +7 -0
  87. package/dist/search/types.d.ts.map +1 -1
  88. package/dist/{shell-translations.pt-br-2GWRQRRP.js → shell-translations.pt-br-ANQ64XTT.js} +75 -3
  89. package/dist/shell-translations.pt-br-ANQ64XTT.js.map +1 -0
  90. package/dist/telemetry/errors.d.ts +87 -0
  91. package/dist/telemetry/errors.d.ts.map +1 -0
  92. package/dist/testing/index.js +4 -1
  93. package/dist/testing.d.ts +2 -0
  94. package/dist/testing.d.ts.map +1 -1
  95. package/dist/types/analytics.d.ts +39 -0
  96. package/dist/types/analytics.d.ts.map +1 -1
  97. package/dist/types/crud.d.ts +35 -1
  98. package/dist/types/crud.d.ts.map +1 -1
  99. package/dist/types/plugins.d.ts +94 -0
  100. package/dist/types/plugins.d.ts.map +1 -1
  101. package/package.json +7 -3
  102. package/dist/chunk-6RBW2Y5K.js +0 -42
  103. package/dist/chunk-6RBW2Y5K.js.map +0 -1
  104. package/dist/chunk-732GZEUI.js.map +0 -1
  105. package/dist/chunk-CPMHCTX3.js +0 -77
  106. package/dist/chunk-CPMHCTX3.js.map +0 -1
  107. package/dist/chunk-JO7Z2AOE.js +0 -863
  108. package/dist/chunk-JO7Z2AOE.js.map +0 -1
  109. package/dist/chunk-M27JPX3K.js.map +0 -1
  110. package/dist/integrations.d.ts +0 -159
  111. package/dist/integrations.d.ts.map +0 -1
  112. package/dist/shell-translations.pt-br-2GWRQRRP.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/registry/registry-class.ts","../src/registry/entities.ts"],"names":[],"mappings":"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","file":"chunk-EWKX4VUM.js","sourcesContent":["import type { BlockPreset, BlockSetting, BlockStability } from './block-schema'\n\n// ---------------------------------------------------------------------------\n// The Registry class and its meta envelope, in a leaf module.\n//\n// Split from ./index so sibling modules that instantiate a registry at module\n// scope (./handles) can import the class without evaluating the whole registry\n// barrel — ESM hoists `export … from` like any import, so a barrel that both\n// defines the class and re-exports an instantiating sibling dead-locks on\n// itself. Public API is unchanged: ./index re-exports everything here.\n// ---------------------------------------------------------------------------\n\n/** A JSON Schema object (loosely typed; validated by tooling, not at runtime). */\nexport type JsonSchema = Record<string, unknown>\n\nexport type RegistrySource = 'sdk' | 'plugin' | 'app'\n\n/**\n * A child a block cannot function without — re-inserted at its template index\n * when a generated or edited tree drops it (WooCommerce's `use-forced-layout`).\n * `props` seeds the re-inserted instance; the child's own setting defaults fill\n * whatever `props` leaves unsaid.\n */\nexport interface RequiredBlockChild {\n type: string\n /** Stable id for the re-inserted node. Defaults to `type`. */\n id?: string\n props?: Record<string, unknown>\n}\n\n// --- Data needs (spine M3) ----------------------------------------------------\n// Part of the meta envelope because it is a DECLARATION, not code: a block says\n// which loader feeds it and how the loader's params are filled. The page-level\n// resolver reads it; validateStore checks it; the document can carry it.\n\n/** A param value bound to a route param of the page being rendered\n * (`{ category: { $param: 'slug' } }`). */\nexport interface LoaderParamRef {\n $param: string\n}\n\n/** A param value bound to one of the declaring block instance's own props\n * (`{ limit: { $prop: 'limit' } }`). Setting defaults fill unset props, so the\n * declared need and the rendered block always agree on the value. */\nexport interface LoaderPropRef {\n $prop: string\n}\n\n/**\n * One named data need: which loader, with which params. A param value is a\n * JSON literal (a document-level constant), a {@link LoaderParamRef} or a\n * {@link LoaderPropRef}.\n */\nexport interface BlockDataNeed {\n /** Registered loader id — unknown ids are an I2 hard error. */\n loader: string\n params?: Record<string, unknown>\n}\n\n/** A block's named data needs (`{ products: { loader: 'products.list' } }`). */\nexport type BlockDataNeeds = Record<string, BlockDataNeed>\n\nexport interface RegistryMeta {\n /** Human title — the canonical name of the uniform meta envelope. `label` is\n * the legacy alias; `register()` folds the two so either spelling reads back\n * through both fields. */\n title?: string\n /** Human label for the platform editor. @see title */\n label?: string\n description?: string\n /** Where this artifact came from (for introspection / conflict reporting). */\n source?: RegistrySource\n /** Owning plugin id, when source is 'plugin'. */\n pluginId?: string\n /** JSON Schema for this artifact's props/config — drives the visual editor\n * and constrains AI generation. Optional but strongly encouraged.\n *\n * Prefer declaring `settings` and letting `defineBlock` compile this: the two\n * must not be hand-maintained side by side or they drift. */\n propsSchema?: JsonSchema\n /** Authoring-level prop declaration. Compiles to {@link propsSchema}. */\n settings?: readonly BlockSetting[]\n /** Named starting points offered when the artifact is inserted. */\n presets?: readonly BlockPreset[]\n /**\n * Surfaces this artifact may be placed on. Absent means \"anywhere\".\n *\n * The vocabulary belongs to the surface, not to core — the storefront uses\n * page kinds (`home`, `catalog`, `product`, …), an admin scaffold uses its\n * own. Core only carries the constraint so tooling can enforce it uniformly.\n */\n enabledOn?: readonly string[]\n /** Contract stability. Absent means `stable`. */\n stability?: BlockStability\n /** SDK/plugin version this entry first appeared in (semver string). Part of\n * the uniform meta envelope so tooling can say \"since 0.9\" about any\n * registry entry — blocks today, entities/rules/actions later. */\n since?: string\n /** One-line description of the value this entry resolves to. Loaders declare\n * it so the agent knows what a data need yields without running it. */\n output?: string\n /**\n * Named data needs this entry resolves through the page-level resolver\n * (spine M3): `{ products: { loader: 'products.list', params: {...} } }`.\n * Declared on blocks; a document block instance may add or override needs\n * with the same shape. Loaders are the ONLY read path (I11) — a block with a\n * `data` declaration must not fetch for itself.\n */\n data?: BlockDataNeeds\n\n // --- Composition constraints (WooCommerce block.json vocabulary) ------------\n // Declared as data so the validator, the renderer and the editor enforce the\n // same rules from one declaration (spine I7). All optional; absent means\n // unconstrained. Enforced by `checkBlockConstraints` and at render time.\n\n /** Block ids this artifact may ONLY be a DIRECT child of (block.json `parent`).\n * A block declaring this cannot sit at a tree root. */\n parent?: readonly string[]\n /** Block ids that must appear somewhere ABOVE this artifact, at any depth\n * (block.json `ancestor`). Weaker than `parent`; both may be declared. */\n ancestor?: readonly string[]\n /** Context keys this artifact reads at runtime (block.json `usesContext`).\n * A placement where no ancestor provides them is reported as advisory —\n * the surface (page, slot) may supply them instead. */\n usesContext?: readonly string[]\n /** Context keys this artifact provides to its descendants\n * (block.json `providesContext`). */\n providesContext?: readonly string[]\n /** May this artifact appear more than once in one tree\n * (block.json `supports.multiple`)? Absent means true. */\n allowMultiple?: boolean\n /** Children this artifact cannot function without — re-inserted by\n * `repairBlockTree` when missing (use-forced-layout). Order is the template\n * order, which decides the index a missing child is re-inserted at. */\n requiredChildren?: readonly RequiredBlockChild[]\n}\n\nexport interface RegistryEntry<T> {\n id: string\n value: T\n meta: RegistryMeta\n}\n\n/**\n * The uniform meta envelope, as data. Every registry — blocks today, entities,\n * rules and actions later — describes its entries through this one shape, so a\n * catalog consumer (the editor, the AI, `fayz catalog`) reads N registries with\n * one parser. Richer per-kind descriptors (e.g. `BlockDescriptor` with settings\n * and presets) extend this rather than replacing it.\n */\nexport interface RegistryEntryDescriptor {\n id: string\n /** The owning registry's kind ('block', 'handle', …). */\n kind: string\n title?: string\n description?: string\n /** JSON Schema for the entry's props/config, when declared. */\n schema?: JsonSchema\n stability: BlockStability\n since?: string\n source?: RegistrySource\n pluginId?: string\n}\n\n/** A typed, introspectable id→value map. Last registration wins (so an app's\n * registry.tsx can override an SDK artifact by re-registering its id). */\nexport class Registry<T> {\n private readonly entries = new Map<string, RegistryEntry<T>>()\n\n constructor(readonly kind: string) {}\n\n register(id: string, value: T, meta: RegistryMeta = {}): void {\n // Fold the title/label alias both ways at the door, so consumers written\n // against either generation of the meta shape read the same string.\n const title = meta.title ?? meta.label\n this.entries.set(id, { id, value, meta: title === undefined ? meta : { ...meta, title, label: title } })\n }\n\n get(id: string): T | undefined {\n return this.entries.get(id)?.value\n }\n\n getEntry(id: string): RegistryEntry<T> | undefined {\n return this.entries.get(id)\n }\n\n has(id: string): boolean {\n return this.entries.has(id)\n }\n\n list(): RegistryEntry<T>[] {\n return Array.from(this.entries.values())\n }\n\n ids(): string[] {\n return Array.from(this.entries.keys())\n }\n\n /**\n * Every entry reduced to the uniform meta envelope, sorted by id.\n *\n * Sorted for the same reason as `describeBlocks`: this feeds prompts,\n * documents and generated catalogs, and registration order is an\n * implementation detail that would make every diff noisy.\n */\n describe(): RegistryEntryDescriptor[] {\n return this.list()\n .map(({ id, meta }) => ({\n id,\n kind: this.kind,\n title: meta.title ?? meta.label,\n description: meta.description,\n schema: meta.propsSchema,\n stability: meta.stability ?? 'stable',\n since: meta.since,\n source: meta.source,\n pluginId: meta.pluginId,\n }))\n .sort((a, b) => a.id.localeCompare(b.id))\n }\n\n clear(): void {\n this.entries.clear()\n }\n}\n\n/** True for app-local custom artifacts (`custom:*`). */\nexport function isCustomId(id: string): boolean {\n return id.startsWith('custom:')\n}\n","import { Registry } from './registry-class'\nimport type { JsonSchema, RegistryEntryDescriptor, RegistrySource } from './registry-class'\nimport type { FieldDef, FieldType } from '../types/crud'\n\n// ---------------------------------------------------------------------------\n// Entities — a new KIND of data as one declaration (spine §3 L1, milestone M4).\n//\n// defineEntity('store_location', { fields, scope, access, indexes }) is the\n// whole authoring surface. From that single declaration the system emits:\n//\n// 1. the JSON Schema a record is validated against on WRITE (I1 — same\n// one-declaration→schema emission as block settings → propsSchema),\n// 2. the storage descriptor (which table holds the records, so a hot entity\n// can be promoted to typed columns behind the I5 indirection),\n// 3. the tenant-scoping RLS policy SQL (generated in @fayz-ai/shop from this\n// declaration — nobody hand-writes a policy, I6),\n// 4. the query surface (the storefront's entity.* loaders),\n// 5. the admin CRUD form descriptor (entityAdminForm, targeting the existing\n// FieldDef vocabulary the SaaS CRUD renders).\n//\n// This module is the DECLARATION layer only, deliberately compile-target-\n// agnostic (I11): nothing here knows SQL, Supabase, or Shopify metaobjects.\n// The physical compilation lives with the backend that owns it.\n//\n// I2 everywhere: an unknown entity, field type, or field reference is a hard\n// error naming the valid set — never a silent drop.\n//\n// Leaf-module discipline (see registry-class.ts): instantiates registries at\n// module scope, so it imports only sibling leaves, never ./index.\n// ---------------------------------------------------------------------------\n\n/** The field-type vocabulary an entity may declare. */\nexport type EntityFieldType =\n | 'text'\n | 'richtext'\n | 'number'\n | 'boolean'\n | 'json'\n | 'image'\n | 'url'\n | 'ref'\n | 'point'\n | 'date'\n | 'datetime'\n | 'select'\n\n/** The vocabulary as a runtime value, for catalogs and I2 error messages.\n * `satisfies` + exhaustiveness keep the union and the list from drifting.\n * It also mirrors the CHECK on plg_entity_fields.type (migration 035) — a type\n * is a MODEL change, in both places at once, never an insert. */\nexport const ENTITY_FIELD_TYPES = [\n 'text',\n 'richtext',\n 'number',\n 'boolean',\n 'json',\n 'image',\n 'url',\n 'ref',\n 'point',\n 'date',\n 'datetime',\n 'select',\n] as const satisfies readonly EntityFieldType[]\ntype MissingEntityFieldType = Exclude<EntityFieldType, (typeof ENTITY_FIELD_TYPES)[number]>\nconst _entityFieldTypesExhaustive: [MissingEntityFieldType] extends [never] ? true : never = true\nvoid _entityFieldTypesExhaustive\n\n/**\n * Bounds a value must respect beyond its type. Kept as data, not code, because\n * a merchant defines these in the admin and they have to survive the round trip\n * through plg_entity_fields.validation without anything being compiled.\n */\nexport interface EntityFieldValidation {\n /** Numbers: inclusive bounds. */\n min?: number\n max?: number\n /** Strings: inclusive length bounds. */\n minLength?: number\n maxLength?: number\n /** Strings: an anchored-as-written regular expression. */\n pattern?: string\n}\n\n/** One choice of a `select` field. The value is what lands in custom_fields. */\nexport interface EntityFieldOption {\n value: string\n label?: string\n}\n\nexport interface EntityField {\n type: EntityFieldType\n /** Human label — drives the admin form and the agent's understanding. */\n label?: string\n help?: string\n required?: boolean\n default?: unknown\n /** `ref` only: the entity key this field points to (stores that entity's record id). */\n entity?: string\n /** `select` only: the closed set of values. */\n options?: readonly EntityFieldOption[]\n validation?: EntityFieldValidation\n}\n\nexport type EntityReadAccess = 'public' | 'staff'\n\n/**\n * Who reads and who writes. `write` is 'staff' only on purpose: shopper-writable\n * entities (reviews) need the action/rate-limit layer (M7), not an RLS grant.\n */\nexport interface EntityAccess {\n read: EntityReadAccess\n write: 'staff'\n}\n\n/** Where records live. Generic jsonb storage first (I5); promoting a hot entity\n * to typed columns changes THIS value, and nothing else callers see. */\nexport interface EntityStorageDescriptor {\n mode: 'generic' | 'dedicated'\n /** Physical table. 'generic' mode shares it across entities. */\n table: string\n}\n\nexport interface EntityDeclarationInput {\n /** Human title (singular). Defaults to the key. */\n title?: string\n description?: string\n fields: Record<string, EntityField>\n /** Only 'tenant' exists today: every record belongs to one store. */\n scope?: 'tenant'\n /** Default: staff-only both ways — public exposure is opt-in, never implied. */\n access?: Partial<EntityAccess>\n /** Field-name tuples to index for querying/filtering. */\n indexes?: readonly (readonly string[])[]\n /** Field whose value titles a record in lists. Default: first text field. */\n titleField?: string\n /** Fields blocks display by default (entityList). Default: every non-json field. */\n displayFields?: readonly string[]\n}\n\nexport interface EntityDeclaration {\n key: string\n title: string\n description?: string\n fields: Record<string, EntityField>\n scope: 'tenant'\n access: EntityAccess\n indexes: readonly (readonly string[])[]\n titleField?: string\n displayFields: readonly string[]\n storage: EntityStorageDescriptor\n}\n\n/** The shared jsonb records table (see @fayz-ai/shop migrations 0030). */\nexport const GENERIC_ENTITY_TABLE = 'plg_entity_records'\n\n/** Entity keys become table/policy-name fragments and document keys: snake_case. */\nconst ENTITY_KEY_RE = /^[a-z][a-z0-9_]*$/\nconst FIELD_NAME_RE = /^[a-z][a-z0-9_]*$/\n\n/** Structural record columns a declared field must not shadow. */\nexport const RESERVED_ENTITY_FIELDS = ['id', 'slug', 'entity', 'tenant_id', 'created_at', 'updated_at'] as const\n\nexport const entityDeclarationRegistry = new Registry<EntityDeclaration>('entity')\n\nfunction fail(message: string, valid?: readonly string[]): never {\n throw new Error(valid?.length ? `${message} Valid: ${valid.join(', ')}.` : message)\n}\n\nfunction normalizeDeclaration(key: string, input: EntityDeclarationInput): EntityDeclaration {\n if (!ENTITY_KEY_RE.test(key)) {\n fail(`defineEntity: \"${key}\" is not a valid entity key — keys are snake_case (${ENTITY_KEY_RE}).`)\n }\n const fieldNames = Object.keys(input.fields ?? {})\n if (fieldNames.length === 0) {\n fail(`defineEntity(\"${key}\"): an entity declares at least one field.`)\n }\n for (const [name, field] of Object.entries(input.fields)) {\n if (!FIELD_NAME_RE.test(name)) {\n fail(`defineEntity(\"${key}\"): \"${name}\" is not a valid field name — fields are snake_case (${FIELD_NAME_RE}).`)\n }\n if ((RESERVED_ENTITY_FIELDS as readonly string[]).includes(name)) {\n fail(`defineEntity(\"${key}\"): \"${name}\" is a structural record column and cannot be a declared field.`, RESERVED_ENTITY_FIELDS)\n }\n if (!(ENTITY_FIELD_TYPES as readonly string[]).includes(field?.type as string)) {\n fail(`defineEntity(\"${key}\"): field \"${name}\" has unknown type \"${String(field?.type)}\".`, ENTITY_FIELD_TYPES)\n }\n if (field.type === 'ref' && !field.entity) {\n fail(`defineEntity(\"${key}\"): ref field \"${name}\" must name the entity it points to ({ type: 'ref', entity: '<key>' }).`)\n }\n }\n const knows = (name: string, where: string): void => {\n if (!fieldNames.includes(name)) {\n fail(`defineEntity(\"${key}\"): ${where} references undeclared field \"${name}\".`, fieldNames)\n }\n }\n for (const index of input.indexes ?? []) {\n for (const name of index) knows(name, 'an index')\n }\n if (input.titleField) knows(input.titleField, 'titleField')\n for (const name of input.displayFields ?? []) knows(name, 'displayFields')\n\n const titleField =\n input.titleField ?? fieldNames.find((name) => input.fields[name]!.type === 'text')\n const displayFields =\n input.displayFields ?? fieldNames.filter((name) => input.fields[name]!.type !== 'json')\n\n return {\n key,\n title: input.title ?? key,\n description: input.description,\n fields: input.fields,\n scope: input.scope ?? 'tenant',\n access: { read: input.access?.read ?? 'staff', write: 'staff' },\n indexes: input.indexes ?? [],\n titleField,\n displayFields,\n storage: { mode: 'generic', table: GENERIC_ENTITY_TABLE },\n }\n}\n\n/**\n * Declare an entity. One call → registry entry on the uniform meta envelope,\n * with the record JSON Schema as `propsSchema` — the same emission discipline\n * as `defineBlock` (I1), so every catalog consumer reads entities and blocks\n * with one parser.\n */\nexport function defineEntity(\n key: string,\n input: EntityDeclarationInput,\n meta: { source?: RegistrySource; pluginId?: string; since?: string } = {},\n): EntityDeclaration {\n const declaration = normalizeDeclaration(key, input)\n entityDeclarationRegistry.register(key, declaration, {\n title: declaration.title,\n description: declaration.description,\n propsSchema: entityRecordSchema(declaration),\n source: meta.source ?? 'app',\n pluginId: meta.pluginId,\n since: meta.since,\n })\n return declaration\n}\n\nfunction formatValidEntities(): string {\n const ids = entityDeclarationRegistry.ids().sort()\n return ids.length\n ? `Declared entities: ${ids.join(', ')}`\n : 'No entities are declared — call defineEntity(key, declaration) first.'\n}\n\n/** Resolve a declaration or throw naming the valid set — the I2 contract. */\nexport function resolveEntityDeclaration(key: string): EntityDeclaration {\n const declaration = entityDeclarationRegistry.get(key)\n if (!declaration) throw new Error(`Unknown entity \"${key}\". ${formatValidEntities()}`)\n return declaration\n}\n\nexport function hasEntityDeclaration(key: string): boolean {\n return entityDeclarationRegistry.has(key)\n}\n\n/** All declared entity keys, sorted. */\nexport function listEntityDeclarations(): string[] {\n return entityDeclarationRegistry.ids().sort()\n}\n\n/** Test seam — a suite that declares entities must not leak into the next. */\nexport function clearEntityDeclarations(): void {\n entityDeclarationRegistry.clear()\n}\n\n// --- JSON Schema emission (I1) ------------------------------------------------\n\nconst FIELD_FORMAT: Partial<Record<EntityFieldType, string>> = {\n image: 'uri',\n url: 'uri',\n date: 'date',\n datetime: 'date-time',\n}\n\n/** Declared bounds, projected onto the JSON Schema node the agent generates\n * against — so the contract states them instead of only the validator. */\nfunction applyValidation(node: JsonSchema, field: EntityField): void {\n const v = field.validation\n if (!v) return\n if (field.type === 'number') {\n if (v.min !== undefined) node.minimum = v.min\n if (v.max !== undefined) node.maximum = v.max\n return\n }\n if (v.minLength !== undefined) node.minLength = v.minLength\n if (v.maxLength !== undefined) node.maxLength = v.maxLength\n if (v.pattern !== undefined) node.pattern = v.pattern\n}\n\nfunction fieldToJsonSchema(name: string, field: EntityField): JsonSchema {\n const node: JsonSchema = {\n title: field.label ?? name,\n // The control survives the compile, exactly as in block settings: a `ref`\n // is a string in JSON Schema terms, but an editor rendering it as a text\n // input (instead of a record picker) is a bug.\n 'x-fayz-control': field.type,\n }\n if (field.help) node.description = field.help\n if (field.default !== undefined) node.default = field.default\n const format = FIELD_FORMAT[field.type]\n if (format) node.format = format\n\n switch (field.type) {\n case 'number':\n node.type = 'number'\n applyValidation(node, field)\n return node\n case 'boolean':\n node.type = 'boolean'\n return node\n case 'json':\n // Any JSON value. The one field type with no shape on purpose — it is\n // the declared escape hatch, not an accident like Medusa's `metadata`.\n return node\n case 'point':\n node.type = 'object'\n node.properties = { lat: { type: 'number' }, lng: { type: 'number' } }\n node.required = ['lat', 'lng']\n node.additionalProperties = false\n return node\n case 'ref':\n node.type = 'string'\n node['x-fayz-ref-entity'] = field.entity\n return node\n case 'select':\n node.type = 'string'\n node.enum = (field.options ?? []).map((option) => option.value)\n return node\n default:\n // text, richtext, image, url, date, datetime\n node.type = 'string'\n applyValidation(node, field)\n return node\n }\n}\n\n/**\n * The JSON Schema one record's `data` is validated against — on write, in the\n * admin form, and as the agent's generation contract. `additionalProperties:\n * false` is the schema-level I2: a field the declaration does not know is an\n * error, not silently-unfilterable baggage (the Medusa `metadata` disease).\n */\nexport function entityRecordSchema(declaration: Pick<EntityDeclaration, 'fields' | 'title' | 'description'>): JsonSchema {\n const properties: Record<string, JsonSchema> = {}\n const required: string[] = []\n for (const [name, field] of Object.entries(declaration.fields)) {\n properties[name] = fieldToJsonSchema(name, field)\n if (field.required) required.push(name)\n }\n const schema: JsonSchema = {\n type: 'object',\n title: declaration.title,\n properties,\n additionalProperties: false,\n }\n if (declaration.description) schema.description = declaration.description\n if (required.length > 0) schema.required = required\n return schema\n}\n\n// --- Write-time validation ----------------------------------------------------\n\nexport interface EntityRecordIssue {\n /** Dotted path into the record data ('hours', 'geo.lat'). */\n path: string\n code: 'unknown-field' | 'missing-field' | 'invalid-value'\n message: string\n /** The valid set, on unknown-id errors — what the agent corrects on. */\n valid?: string[]\n}\n\nfunction typeOf(value: unknown): string {\n return Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value\n}\n\n/** Declared bounds, checked after the type already matched. A malformed\n * `pattern` is the merchant's typo, not a crash: it fails the value it was\n * meant to guard rather than taking the whole write down. */\nfunction checkBounds(\n issues: EntityRecordIssue[],\n name: string,\n field: EntityField,\n value: string | number,\n): void {\n const v = field.validation\n if (!v) return\n const invalid = (message: string) => issues.push({ path: name, code: 'invalid-value', message })\n\n if (typeof value === 'number') {\n if (v.min !== undefined && value < v.min) invalid(`\"${name}\" is below the minimum of ${v.min}`)\n if (v.max !== undefined && value > v.max) invalid(`\"${name}\" is above the maximum of ${v.max}`)\n return\n }\n if (v.minLength !== undefined && value.length < v.minLength) {\n invalid(`\"${name}\" is shorter than ${v.minLength} character(s)`)\n }\n if (v.maxLength !== undefined && value.length > v.maxLength) {\n invalid(`\"${name}\" is longer than ${v.maxLength} character(s)`)\n }\n if (v.pattern !== undefined) {\n let re: RegExp | null = null\n try {\n re = new RegExp(v.pattern)\n } catch {\n invalid(`\"${name}\" has an unreadable pattern in its definition`)\n }\n if (re && !re.test(value)) invalid(`\"${name}\" does not match the expected format`)\n }\n}\n\n/**\n * Validate one record's `data` against a declaration — the write gate every\n * EntityStore implementation runs. Pure and total: returns issues, never throws.\n */\nexport function validateEntityRecordData(\n declaration: Pick<EntityDeclaration, 'fields'>,\n data: unknown,\n): EntityRecordIssue[] {\n const issues: EntityRecordIssue[] = []\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n return [{ path: '', code: 'invalid-value', message: `record data is an object, got ${typeOf(data)}` }]\n }\n const record = data as Record<string, unknown>\n const fieldNames = Object.keys(declaration.fields)\n\n for (const [name, value] of Object.entries(record)) {\n const field = declaration.fields[name]\n if (!field) {\n issues.push({\n path: name,\n code: 'unknown-field',\n message: `field \"${name}\" is not declared by this entity`,\n valid: fieldNames,\n })\n continue\n }\n if (value === null || value === undefined) continue // absence checked below\n switch (field.type) {\n case 'number':\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n issues.push({ path: name, code: 'invalid-value', message: `\"${name}\" expects a number, got ${typeOf(value)}` })\n } else {\n checkBounds(issues, name, field, value)\n }\n break\n case 'boolean':\n if (typeof value !== 'boolean') {\n issues.push({ path: name, code: 'invalid-value', message: `\"${name}\" expects a boolean, got ${typeOf(value)}` })\n }\n break\n case 'json':\n break // any JSON value\n case 'point': {\n const point = value as Record<string, unknown>\n if (\n typeOf(value) !== 'object' ||\n typeof point.lat !== 'number' ||\n typeof point.lng !== 'number' ||\n Object.keys(point).length !== 2\n ) {\n issues.push({ path: name, code: 'invalid-value', message: `\"${name}\" expects {lat: number, lng: number}` })\n }\n break\n }\n case 'select': {\n const allowed = (field.options ?? []).map((option) => option.value)\n if (typeof value !== 'string') {\n issues.push({ path: name, code: 'invalid-value', message: `\"${name}\" expects a string, got ${typeOf(value)}` })\n } else if (!allowed.includes(value)) {\n issues.push({\n path: name,\n code: 'invalid-value',\n message: `\"${name}\" does not accept \"${value}\"`,\n valid: allowed,\n })\n }\n break\n }\n default:\n // text, richtext, image, url, date, datetime, ref — strings on the wire.\n if (typeof value !== 'string') {\n issues.push({ path: name, code: 'invalid-value', message: `\"${name}\" expects a string, got ${typeOf(value)}` })\n } else {\n checkBounds(issues, name, field, value)\n }\n }\n }\n\n for (const [name, field] of Object.entries(declaration.fields)) {\n if (field.required && (record[name] === undefined || record[name] === null || record[name] === '')) {\n issues.push({ path: name, code: 'missing-field', message: `required field \"${name}\" is missing` })\n }\n }\n return issues\n}\n\n// --- Catalog ------------------------------------------------------------------\n\n/** The uniform envelope plus the entity-specific fields the agent reads. */\nexport interface EntityDescriptor extends RegistryEntryDescriptor {\n /** JSON Schema for a record's data (alias of `schema`, named for intent). */\n recordSchema?: JsonSchema\n access: EntityAccess\n scope: 'tenant'\n storage: EntityStorageDescriptor\n indexes: readonly (readonly string[])[]\n titleField?: string\n displayFields: readonly string[]\n}\n\n/** Every declared entity reduced to its descriptor, sorted by key — what\n * describeStore publishes and the agent generates against. */\nexport function describeEntities(): EntityDescriptor[] {\n return entityDeclarationRegistry.describe().map((base) => {\n const declaration = entityDeclarationRegistry.get(base.id)!\n return {\n ...base,\n recordSchema: base.schema,\n access: declaration.access,\n scope: declaration.scope,\n storage: declaration.storage,\n indexes: declaration.indexes,\n titleField: declaration.titleField,\n displayFields: declaration.displayFields,\n }\n })\n}\n\n// --- Generated admin CRUD descriptor -------------------------------------------\n\n/** How each entity field type is edited. Targets the existing FieldDef\n * vocabulary (packages/core/src/types/crud.ts) that the SaaS CRUD renders —\n * the descriptor is data, so a form is derivable without new machinery. */\nconst FIELD_TYPE_TO_INPUT: Record<EntityFieldType, FieldType> = {\n text: 'text',\n richtext: 'markdown',\n number: 'number',\n boolean: 'boolean',\n // JSON and point have no dedicated control yet; they degrade to text inputs\n // with a hint, which is honest — the descriptor still names the real type in\n // the record schema, so a richer control can adopt them without a migration.\n json: 'textarea',\n point: 'text',\n image: 'image',\n url: 'url',\n ref: 'relation',\n date: 'date',\n datetime: 'datetime',\n select: 'select',\n}\n\nexport interface EntityAdminForm {\n entity: string\n title: string\n fields: FieldDef[]\n}\n\n/**\n * The admin CRUD form for an entity, emitted from the declaration as data.\n * Field order is declaration order; labels default to the field name; `ref`\n * fields become relation pickers over the generic records table filtered to\n * the target entity.\n */\nexport function entityAdminForm(declaration: EntityDeclaration): EntityAdminForm {\n const fields: FieldDef[] = Object.entries(declaration.fields).map(([name, field]) => {\n const def: FieldDef = {\n key: name,\n label: field.label ?? name,\n type: FIELD_TYPE_TO_INPUT[field.type],\n showInForm: true,\n showInTable: declaration.displayFields.includes(name),\n }\n if (field.required) def.required = true\n if (field.help) def.hint = field.help\n if (field.default !== undefined) def.defaultValue = field.default\n if (field.type === 'json') def.hint = field.help ?? 'JSON value'\n if (field.type === 'point') def.hint = field.help ?? 'lat,lng'\n if (field.type === 'select') {\n def.options = (field.options ?? []).map((option) => ({ label: option.label ?? option.value, value: option.value }))\n }\n if (field.type === 'ref' && field.entity) {\n def.relation = {\n table: declaration.storage.table,\n valueField: 'id',\n labelField: 'slug',\n filter: { entity: field.entity },\n }\n }\n return def\n })\n return { entity: declaration.key, title: declaration.title, fields }\n}\n\n// --- Custom fields on core records ---------------------------------------------\n// Extra fields on a record the SDK already owns are not a new entity, and not a\n// new column: they are keys inside `custom_fields` (migration 034), governed by\n// plg_entity_fields (035). A key the registry does not know is a write error —\n// unlike Medusa's `metadata` (76 of 148 models, validated as z.unknown, and\n// silently unfilterable), and unlike CRM's people.metadata->'fields' today.\n//\n// Two halves make the registry, and they merge:\n// declared — this module. Comes from plugin/app code, re-asserted on deploy.\n// merchant — plg_entity_fields rows, defined in the admin with no deploy.\n// This file owns the declared half only; @fayz-ai/core/fields loads the other\n// and merges them. Declared wins on a collision, so a deploy can adopt a key a\n// merchant invented without either side losing work.\n\n/** The record kind a field hangs off: an archetype name, snake_case. Open on\n * purpose — the next archetype is a value, not a release. Mirrors the CHECK on\n * plg_entity_fields.reference. */\nconst REFERENCE_RE = /^[a-z][a-z0-9_]*$/\n\nexport interface CustomFieldsDeclaration {\n reference: string\n fields: Record<string, EntityField>\n}\n\nexport const customFieldsRegistry = new Registry<CustomFieldsDeclaration>('customFields')\n\n/**\n * Declare custom fields on a core record kind. One declaration per reference\n * (re-declaring replaces — registry semantics, so an app's registry.tsx wins).\n */\nexport function defineCustomFields(\n reference: string,\n fields: Record<string, EntityField>,\n meta: { source?: RegistrySource; pluginId?: string } = {},\n): CustomFieldsDeclaration {\n if (!REFERENCE_RE.test(reference)) {\n fail(`defineCustomFields: \"${reference}\" is not a valid record kind (${REFERENCE_RE}).`)\n }\n for (const [name, field] of Object.entries(fields)) {\n if (!FIELD_NAME_RE.test(name)) {\n fail(`defineCustomFields(\"${reference}\"): \"${name}\" is not a valid field name (${FIELD_NAME_RE}).`)\n }\n if (!(ENTITY_FIELD_TYPES as readonly string[]).includes(field?.type as string)) {\n fail(`defineCustomFields(\"${reference}\"): field \"${name}\" has unknown type \"${String(field?.type)}\".`, ENTITY_FIELD_TYPES)\n }\n if (field.type === 'select' && !(field.options ?? []).length) {\n fail(`defineCustomFields(\"${reference}\"): select field \"${name}\" declares no options.`)\n }\n }\n const declaration: CustomFieldsDeclaration = { reference, fields }\n customFieldsRegistry.register(reference, declaration, {\n title: `Custom fields: ${reference}`,\n propsSchema: entityRecordSchema({ title: `${reference} custom fields`, fields }),\n source: meta.source ?? 'app',\n pluginId: meta.pluginId,\n })\n return declaration\n}\n\n/**\n * The declared half for a record kind. Returns an empty set rather than\n * throwing: a tenant whose only fields came from the admin is the normal case,\n * and the merge in @fayz-ai/core/fields is what completes the picture.\n */\nexport function declaredCustomFields(reference: string): Record<string, EntityField> {\n return customFieldsRegistry.get(reference)?.fields ?? {}\n}\n\nexport function hasCustomFieldsDeclaration(reference: string): boolean {\n return customFieldsRegistry.has(reference)\n}\n\n/** Test seam. */\nexport function clearCustomFieldsDeclarations(): void {\n customFieldsRegistry.clear()\n}\n"]}
@@ -0,0 +1,289 @@
1
+ import { isConnectorCategory, CONNECTOR_CATEGORIES, requestPlaneSpec, connectorPlanes, invocationPlane, connectorSubscribes, permissionActions, isEventPermission, connectorEntities, connectorSubscribesTo } from './chunk-7GJTLBG3.js';
2
+
3
+ // src/testing.ts
4
+ var PluginContractError = class extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "PluginContractError";
8
+ }
9
+ };
10
+ function fail(scope, msg) {
11
+ throw new PluginContractError(`[${scope}] ${msg}`);
12
+ }
13
+ function nonEmptyString(v) {
14
+ return typeof v === "string" && v.trim().length > 0;
15
+ }
16
+ function assertPluginManifestContract(manifest) {
17
+ const id = manifest?.id;
18
+ const scope = nonEmptyString(id) ? id : "<unknown plugin>";
19
+ for (const field of ["id", "name", "icon", "version"]) {
20
+ if (!nonEmptyString(manifest?.[field])) fail(scope, `manifest.${field} must be a non-empty string`);
21
+ }
22
+ if (!Array.isArray(manifest.navigation)) fail(scope, "manifest.navigation must be an array (use [] for settings-only plugins)");
23
+ if (!Array.isArray(manifest.routes)) fail(scope, "manifest.routes must be an array (use [] for settings-only plugins)");
24
+ for (const [i, nav] of manifest.navigation.entries()) {
25
+ if (!nonEmptyString(nav?.route)) fail(scope, `navigation[${i}].route must be a non-empty string`);
26
+ }
27
+ const routePaths = /* @__PURE__ */ new Set();
28
+ for (const [i, route] of manifest.routes.entries()) {
29
+ if (!nonEmptyString(route?.path)) fail(scope, `routes[${i}].path must be a non-empty string`);
30
+ if (typeof route?.component !== "function") fail(scope, `routes[${i}].component must be a component`);
31
+ if (routePaths.has(route.path)) fail(scope, `duplicate route path "${route.path}"`);
32
+ routePaths.add(route.path);
33
+ }
34
+ for (const [i, nav] of manifest.navigation.entries()) {
35
+ const r = nav.route;
36
+ if (routePaths.size > 0 && !routePaths.has(r)) {
37
+ fail(scope, `navigation[${i}].route "${r}" has no matching route in manifest.routes`);
38
+ }
39
+ }
40
+ const settingIds = /* @__PURE__ */ new Set();
41
+ for (const [i, tab] of (manifest.settings ?? []).entries()) {
42
+ if (!nonEmptyString(tab?.id)) fail(scope, `settings[${i}].id must be a non-empty string`);
43
+ if (!nonEmptyString(tab?.label)) fail(scope, `settings[${i}].label must be a non-empty string`);
44
+ if (typeof tab?.component !== "function") fail(scope, `settings[${i}].component must be a component`);
45
+ if (settingIds.has(tab.id)) fail(scope, `duplicate settings tab id "${tab.id}"`);
46
+ settingIds.add(tab.id);
47
+ }
48
+ for (const [i, feat] of (manifest.declaredFeatures ?? []).entries()) {
49
+ if (!nonEmptyString(feat?.id)) fail(scope, `declaredFeatures[${i}].id must be a non-empty string`);
50
+ }
51
+ for (const [i, src] of (manifest.emitsFrom ?? []).entries()) {
52
+ if (!nonEmptyString(src?.table)) fail(scope, `emitsFrom[${i}].table must be a non-empty string`);
53
+ if (!nonEmptyString(src?.entityKey)) fail(scope, `emitsFrom[${i}].entityKey must be a non-empty string`);
54
+ for (const action of src.actions ?? []) {
55
+ if (!EVENT_ACTIONS.has(action)) fail(scope, `emitsFrom[${i}] has unknown action "${action}"`);
56
+ }
57
+ }
58
+ const functionSlugs = /* @__PURE__ */ new Set();
59
+ for (const [i, fn] of (manifest.functions ?? []).entries()) {
60
+ if (!SLUG.test(fn?.slug ?? "")) fail(scope, `functions[${i}].slug must be kebab-case \u2014 it becomes the deployed function name`);
61
+ if (functionSlugs.has(fn.slug)) fail(scope, `duplicate function slug "${fn.slug}"`);
62
+ functionSlugs.add(fn.slug);
63
+ if (typeof fn.verifyJwt !== "boolean") fail(scope, `functions[${i}].verifyJwt must be a boolean`);
64
+ if (!FUNCTION_INGRESS.has(fn.ingress)) fail(scope, `functions[${i}].ingress "${fn.ingress}" is not one of ${[...FUNCTION_INGRESS].join(", ")}`);
65
+ if (fn.ingress === "fayz" && fn.verifyJwt) fail(scope, `functions[${i}] is reached through the Fayz ingress, so verifyJwt must be false`);
66
+ for (const secret of fn.secrets ?? []) {
67
+ if (!SECRET_NAME.test(secret)) fail(scope, `functions[${i}].secrets must name secrets (SCREAMING_SNAKE_CASE), never carry their values`);
68
+ }
69
+ }
70
+ for (const [i, def] of (manifest.connectors ?? []).entries()) {
71
+ if (def.category !== void 0 && !isConnectorCategory(def.category)) {
72
+ fail(
73
+ scope,
74
+ `connectors[${i}].category "${def.category}" is not a catalogue category \u2014 use one of ${CONNECTOR_CATEGORIES.join(", ")}, taken from the catalogue row with this connector's slug.`
75
+ );
76
+ }
77
+ for (const pattern of def.subscribesTo ?? []) {
78
+ if (!nonEmptyString(pattern)) fail(scope, `connectors[${i}].subscribesTo must hold non-empty patterns`);
79
+ if (pattern.includes("*") && !pattern.endsWith("*")) {
80
+ fail(scope, `connectors[${i}].subscribesTo "${pattern}" \u2014 "*" is only honoured at the end`);
81
+ }
82
+ }
83
+ assertConnectorPermissions(scope, `connectors[${i}]`, def);
84
+ if ((def.planes ?? []).includes("request")) {
85
+ try {
86
+ requestPlaneSpec(def);
87
+ } catch (error) {
88
+ fail(scope, `connectors[${i}] ${error instanceof Error ? error.message : String(error)}`);
89
+ }
90
+ } else if (def.latencyBudgetMs !== void 0 || def.onFailure !== void 0) {
91
+ fail(
92
+ scope,
93
+ `connectors[${i}] declares latencyBudgetMs/onFailure but is not on the request plane \u2014 nothing enforces them, so they read as a guarantee that does not exist.`
94
+ );
95
+ }
96
+ const fieldKeys = new Set((def.fields ?? []).map((f) => f.key));
97
+ const settingKeys = /* @__PURE__ */ new Set();
98
+ for (const [j, setting] of (def.settings ?? []).entries()) {
99
+ const at = `connectors[${i}].settings[${j}]`;
100
+ if (!nonEmptyString(setting?.key)) fail(scope, `${at}.key must be a non-empty string`);
101
+ if (!nonEmptyString(setting?.label)) fail(scope, `${at}.label must be a non-empty string`);
102
+ if (!SETTING_TYPES.has(setting.type)) {
103
+ fail(scope, `${at}.type "${setting.type}" is not one of ${[...SETTING_TYPES].join(", ")}`);
104
+ }
105
+ if (settingKeys.has(setting.key)) fail(scope, `${at} duplicates settings key "${setting.key}"`);
106
+ settingKeys.add(setting.key);
107
+ if (fieldKeys.has(setting.key)) {
108
+ fail(
109
+ scope,
110
+ `${at}.key "${setting.key}" is also a credential field \u2014 a key either authorizes the connection (fields) or configures it (settings), never both.`
111
+ );
112
+ }
113
+ if (setting.type === "select" || setting.type === "multi-select") {
114
+ if (!Array.isArray(setting.options) || setting.options.length === 0) {
115
+ fail(scope, `${at} is a ${setting.type} and must declare options \u2014 that is what replaces a free-text box`);
116
+ }
117
+ for (const [k, option] of setting.options.entries()) {
118
+ if (!nonEmptyString(option?.value)) fail(scope, `${at}.options[${k}].value must be a non-empty string`);
119
+ if (!nonEmptyString(option?.label)) fail(scope, `${at}.options[${k}].label must be a non-empty string`);
120
+ }
121
+ }
122
+ if (setting.pattern !== void 0) {
123
+ if (setting.type !== "text") fail(scope, `${at}.pattern only applies to a text setting`);
124
+ try {
125
+ new RegExp(setting.pattern);
126
+ } catch {
127
+ fail(scope, `${at}.pattern is not a valid regular expression`);
128
+ }
129
+ if (!nonEmptyString(setting.patternHint)) fail(scope, `${at} declares a pattern, so it must declare patternHint`);
130
+ }
131
+ }
132
+ if (settingKeys.size > 0) {
133
+ if (typeof def.getSettings !== "function") fail(scope, `connectors[${i}] declares settings but no getSettings()`);
134
+ if (typeof def.saveSettings !== "function") fail(scope, `connectors[${i}] declares settings but no saveSettings()`);
135
+ }
136
+ const planes = new Set(connectorPlanes(def));
137
+ const momentKeys = /* @__PURE__ */ new Set();
138
+ for (const [j, moment] of (def.invokedAt ?? []).entries()) {
139
+ const at = `connectors[${i}].invokedAt[${j}]`;
140
+ if (!nonEmptyString(moment?.key)) fail(scope, `${at}.key must be a non-empty string`);
141
+ if (!nonEmptyString(moment?.label)) fail(scope, `${at}.label must be a non-empty string`);
142
+ if (momentKeys.has(moment.key)) fail(scope, `${at} duplicates key "${moment.key}"`);
143
+ momentKeys.add(moment.key);
144
+ const plane = invocationPlane(moment);
145
+ if (!planes.has(plane)) {
146
+ fail(scope, `${at} is declared on the ${plane} plane, which connectors[${i}].planes does not include`);
147
+ }
148
+ if (moment.trigger !== void 0) {
149
+ if (plane !== "sync") fail(scope, `${at}.trigger only applies to a sync moment`);
150
+ if (!TRIGGERS.has(moment.trigger)) fail(scope, `${at} has unknown trigger "${moment.trigger}"`);
151
+ }
152
+ const declared = new Set((def.permissions ?? []).map((p) => p.resource));
153
+ for (const resource of moment.touches ?? []) {
154
+ if (!declared.has(resource)) {
155
+ fail(
156
+ scope,
157
+ `${at}.touches names "${resource}", which connectors[${i}].permissions does not declare \u2014 a call site cannot reach what the consent view never showed.`
158
+ );
159
+ }
160
+ }
161
+ }
162
+ for (const [j, auto] of (def.managedAutomations ?? []).entries()) {
163
+ if (!nonEmptyString(auto?.eventKey)) fail(scope, `connectors[${i}].managedAutomations[${j}].eventKey must be a non-empty string`);
164
+ if (!nonEmptyString(auto?.label)) fail(scope, `connectors[${i}].managedAutomations[${j}].label must be a non-empty string`);
165
+ if (!connectorSubscribes(def, auto.eventKey)) {
166
+ fail(scope, `connectors[${i}].managedAutomations[${j}] fires on "${auto.eventKey}", which no subscribesTo pattern covers`);
167
+ }
168
+ }
169
+ }
170
+ for (const [i, mig] of (manifest.migrations ?? []).entries()) {
171
+ for (const table of bespokeConnectorTables(mig?.sql)) {
172
+ fail(
173
+ scope,
174
+ `migrations[${i}] ("${mig?.id ?? "?"}") creates public.${table} \u2014 a connector's own *_integrations / *_sync_log table. Store the connection in plg_connections / plg_sync_runs via createConnectionStore('<connector-id>'): two accounts are two rows separated by instance_key, and connector-specific counters go in stats.`
175
+ );
176
+ }
177
+ }
178
+ if (manifest.navigation.length === 0 && manifest.routes.length === 0 && (manifest.settings ?? []).length === 0 && (manifest.connectors ?? []).length === 0) {
179
+ fail(scope, "plugin contributes no navigation, routes, settings, or connectors \u2014 it would mount but do nothing");
180
+ }
181
+ }
182
+ function assertConnectorPermissions(scope, path, def) {
183
+ const permissions = def.permissions;
184
+ if (permissions === void 0) return;
185
+ if (!Array.isArray(permissions)) fail(scope, `${path}.permissions must be an array`);
186
+ const seen = /* @__PURE__ */ new Set();
187
+ for (const [j, permission] of permissions.entries()) {
188
+ const at = `${path}.permissions[${j}]`;
189
+ if (permission?.kind !== "data" && permission?.kind !== "event") {
190
+ fail(scope, `${at}.kind must be "data" or "event"`);
191
+ }
192
+ if (!nonEmptyString(permission.resource)) fail(scope, `${at}.resource must be a non-empty string`);
193
+ if (!nonEmptyString(permission.reason)) {
194
+ fail(scope, `${at} must declare a reason \u2014 the sentence the tenant judges before authorizing`);
195
+ }
196
+ if (!Array.isArray(permission.actions) || permission.actions.length === 0) {
197
+ fail(scope, `${at}.actions must name at least one action \u2014 a resource with no access is not a permission`);
198
+ }
199
+ const legal = permissionActions(permission.kind);
200
+ for (const action of permission.actions) {
201
+ if (!legal.includes(action)) {
202
+ fail(scope, `${at} asks for "${action}" on the ${permission.kind} resource "${permission.resource}", which only admits ${legal.join(", ")}`);
203
+ }
204
+ }
205
+ if (isEventPermission(permission) && permission.resource.includes("*") && !permission.resource.endsWith("*")) {
206
+ fail(scope, `${at}.resource "${permission.resource}" \u2014 "*" is only honoured at the end`);
207
+ }
208
+ const key = `${permission.kind}:${permission.resource}`;
209
+ if (seen.has(key)) fail(scope, `${at} repeats "${key}" \u2014 one resource, one row, one reason`);
210
+ seen.add(key);
211
+ }
212
+ if (def.entities !== void 0) {
213
+ const declared = new Set(connectorEntities({ permissions }));
214
+ const legacy = new Set(def.entities);
215
+ for (const entity of declared) {
216
+ if (!legacy.has(entity)) {
217
+ fail(
218
+ scope,
219
+ `${path}.permissions reaches "${entity}", which ${path}.entities does not list \u2014 the two describe the same access and must name the same set (drop entities; it is derived).`
220
+ );
221
+ }
222
+ }
223
+ for (const entity of legacy) {
224
+ if (!declared.has(entity)) {
225
+ fail(
226
+ scope,
227
+ `${path}.entities lists "${entity}" with no permission saying what it does with it \u2014 a record type on the consent view with no read/write is a name, not a declaration.`
228
+ );
229
+ }
230
+ }
231
+ }
232
+ if (def.subscribesTo !== void 0) {
233
+ const declared = new Set(connectorSubscribesTo({ permissions }));
234
+ const legacy = new Set(def.subscribesTo);
235
+ for (const pattern of declared) {
236
+ if (!legacy.has(pattern)) {
237
+ fail(
238
+ scope,
239
+ `${path}.permissions listens to "${pattern}", which ${path}.subscribesTo does not \u2014 the ingress filters on that list, so the consent view would promise a fact never delivered.`
240
+ );
241
+ }
242
+ }
243
+ for (const pattern of legacy) {
244
+ if (!declared.has(pattern)) {
245
+ fail(
246
+ scope,
247
+ `${path}.subscribesTo asks for "${pattern}" with no listen permission explaining it \u2014 the connector would receive a fact the tenant was never shown.`
248
+ );
249
+ }
250
+ }
251
+ }
252
+ }
253
+ var BESPOKE_CONNECTOR_TABLE = /\bcreate\s+table\s+(?:if\s+not\s+exists\s+)?(?:[a-z0-9_]+\s*\.\s*)?([a-z0-9_]*(?:_integrations|_sync_log))\b/gi;
254
+ function bespokeConnectorTables(sql) {
255
+ const text = typeof sql === "string" ? sql.replace(/"/g, "") : "";
256
+ const found = /* @__PURE__ */ new Set();
257
+ for (const m of text.matchAll(BESPOKE_CONNECTOR_TABLE)) found.add(m[1].toLowerCase());
258
+ return [...found];
259
+ }
260
+ var EVENT_ACTIONS = /* @__PURE__ */ new Set(["created", "updated", "deleted"]);
261
+ var FUNCTION_INGRESS = /* @__PURE__ */ new Set(["fayz", "none"]);
262
+ var SLUG = /^[a-z0-9][a-z0-9-]*$/;
263
+ var SECRET_NAME = /^[A-Z][A-Z0-9_]*$/;
264
+ var SETTING_TYPES = /* @__PURE__ */ new Set(["text", "select", "multi-select", "toggle"]);
265
+ var AUTH_KINDS = /* @__PURE__ */ new Set(["oauth", "api-key", "mtls"]);
266
+ var DIRECTIONS = /* @__PURE__ */ new Set(["inbound", "outbound", "bidirectional"]);
267
+ var TRIGGERS = /* @__PURE__ */ new Set(["on-write", "scheduled", "manual", "webhook"]);
268
+ function assertConnectorContract(connector) {
269
+ const scope = nonEmptyString(connector?.id) ? `connector:${connector.id}` : "<unknown connector>";
270
+ for (const field of ["id", "provider", "pluginId"]) {
271
+ if (!nonEmptyString(connector?.[field])) fail(scope, `connector.${field} must be a non-empty string`);
272
+ }
273
+ if (!AUTH_KINDS.has(connector.authKind)) fail(scope, `connector.authKind "${connector.authKind}" is not one of ${[...AUTH_KINDS].join(", ")}`);
274
+ if (!Array.isArray(connector.capabilities) || connector.capabilities.length === 0) {
275
+ fail(scope, "connector.capabilities must list at least one capability");
276
+ }
277
+ for (const [i, cap] of connector.capabilities.entries()) {
278
+ if (!nonEmptyString(cap?.entity)) fail(scope, `capabilities[${i}].entity must be a non-empty string`);
279
+ if (!DIRECTIONS.has(cap.direction)) fail(scope, `capabilities[${i}].direction "${cap.direction}" is invalid`);
280
+ if (!Array.isArray(cap.triggers) || cap.triggers.length === 0) fail(scope, `capabilities[${i}].triggers must be non-empty`);
281
+ for (const trig of cap.triggers) {
282
+ if (!TRIGGERS.has(trig)) fail(scope, `capabilities[${i}] has unknown trigger "${trig}"`);
283
+ }
284
+ }
285
+ }
286
+
287
+ export { PluginContractError, assertConnectorContract, assertPluginManifestContract, bespokeConnectorTables };
288
+ //# sourceMappingURL=chunk-IKZR3WSK.js.map
289
+ //# sourceMappingURL=chunk-IKZR3WSK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/testing.ts"],"names":[],"mappings":"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","file":"chunk-IKZR3WSK.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Plugin contract assertions — the integrity half of the deploy gate.\n// ---------------------------------------------------------------------------\n// Framework-agnostic runtime checks (no test-runner dependency) that any\n// plugin's *.test.ts calls to prove its manifest/connector conform to the\n// platform contract BEFORE it can ship. A plugin that fails these would break\n// the host app at mount time (missing route component, duplicate ids, malformed\n// settings tab). Pair with a capability test (does the plugin do its job?) — see\n// docs/plugins/PLUGIN-PATTERNS.md → capability anatomy. These throw on the first violation.\nimport type { PluginManifest } from './types/plugins'\nimport type { Connector } from './integrations'\nimport {\n CONNECTOR_CATEGORIES,\n connectorEntities,\n connectorPlanes,\n connectorSubscribes,\n connectorSubscribesTo,\n grants,\n invocationPlane,\n isConnectorCategory,\n isEventPermission,\n permissionActions,\n requestPlaneSpec,\n} from './integrations'\nimport type { ConnectorPermission } from './integrations'\n\nexport class PluginContractError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'PluginContractError'\n }\n}\n\nfunction fail(scope: string, msg: string): never {\n throw new PluginContractError(`[${scope}] ${msg}`)\n}\n\nfunction nonEmptyString(v: unknown): v is string {\n return typeof v === 'string' && v.trim().length > 0\n}\n\n/**\n * Assert a PluginManifest is structurally sound enough to mount safely.\n * Checks identity, navigation/route wiring, settings tabs, declared features,\n * and id uniqueness. Throws PluginContractError on the first problem.\n */\nexport function assertPluginManifestContract(manifest: PluginManifest): void {\n const id = manifest?.id\n const scope = nonEmptyString(id) ? id : '<unknown plugin>'\n\n for (const field of ['id', 'name', 'icon', 'version'] as const) {\n if (!nonEmptyString(manifest?.[field])) fail(scope, `manifest.${field} must be a non-empty string`)\n }\n\n if (!Array.isArray(manifest.navigation)) fail(scope, 'manifest.navigation must be an array (use [] for settings-only plugins)')\n if (!Array.isArray(manifest.routes)) fail(scope, 'manifest.routes must be an array (use [] for settings-only plugins)')\n\n // Every nav entry must point at a route; every route needs a path + component.\n for (const [i, nav] of manifest.navigation.entries()) {\n if (!nonEmptyString((nav as any)?.route)) fail(scope, `navigation[${i}].route must be a non-empty string`)\n }\n const routePaths = new Set<string>()\n for (const [i, route] of manifest.routes.entries()) {\n if (!nonEmptyString((route as any)?.path)) fail(scope, `routes[${i}].path must be a non-empty string`)\n if (typeof (route as any)?.component !== 'function') fail(scope, `routes[${i}].component must be a component`)\n if (routePaths.has((route as any).path)) fail(scope, `duplicate route path \"${(route as any).path}\"`)\n routePaths.add((route as any).path)\n }\n // A nav entry that links to a route the plugin doesn't declare is dead UI.\n for (const [i, nav] of manifest.navigation.entries()) {\n const r = (nav as any).route\n if (routePaths.size > 0 && !routePaths.has(r)) {\n fail(scope, `navigation[${i}].route \"${r}\" has no matching route in manifest.routes`)\n }\n }\n\n // Settings tabs (the only UI surface integrations need) must be renderable.\n const settingIds = new Set<string>()\n for (const [i, tab] of (manifest.settings ?? []).entries()) {\n if (!nonEmptyString((tab as any)?.id)) fail(scope, `settings[${i}].id must be a non-empty string`)\n if (!nonEmptyString((tab as any)?.label)) fail(scope, `settings[${i}].label must be a non-empty string`)\n if (typeof (tab as any)?.component !== 'function') fail(scope, `settings[${i}].component must be a component`)\n if (settingIds.has((tab as any).id)) fail(scope, `duplicate settings tab id \"${(tab as any).id}\"`)\n settingIds.add((tab as any).id)\n }\n\n for (const [i, feat] of (manifest.declaredFeatures ?? []).entries()) {\n if (!nonEmptyString((feat as any)?.id)) fail(scope, `declaredFeatures[${i}].id must be a non-empty string`)\n }\n\n for (const [i, src] of (manifest.emitsFrom ?? []).entries()) {\n if (!nonEmptyString(src?.table)) fail(scope, `emitsFrom[${i}].table must be a non-empty string`)\n if (!nonEmptyString(src?.entityKey)) fail(scope, `emitsFrom[${i}].entityKey must be a non-empty string`)\n for (const action of src.actions ?? []) {\n if (!EVENT_ACTIONS.has(action)) fail(scope, `emitsFrom[${i}] has unknown action \"${action}\"`)\n }\n }\n\n const functionSlugs = new Set<string>()\n for (const [i, fn] of (manifest.functions ?? []).entries()) {\n if (!SLUG.test(fn?.slug ?? '')) fail(scope, `functions[${i}].slug must be kebab-case — it becomes the deployed function name`)\n if (functionSlugs.has(fn.slug)) fail(scope, `duplicate function slug \"${fn.slug}\"`)\n functionSlugs.add(fn.slug)\n if (typeof fn.verifyJwt !== 'boolean') fail(scope, `functions[${i}].verifyJwt must be a boolean`)\n if (!FUNCTION_INGRESS.has(fn.ingress)) fail(scope, `functions[${i}].ingress \"${fn.ingress}\" is not one of ${[...FUNCTION_INGRESS].join(', ')}`)\n // The ingress authenticates by signature, not by a caller JWT it does not have.\n if (fn.ingress === 'fayz' && fn.verifyJwt) fail(scope, `functions[${i}] is reached through the Fayz ingress, so verifyJwt must be false`)\n for (const secret of fn.secrets ?? []) {\n // A name, never a value — this is the shape that keeps a key out of git.\n if (!SECRET_NAME.test(secret)) fail(scope, `functions[${i}].secrets must name secrets (SCREAMING_SNAKE_CASE), never carry their values`)\n }\n }\n\n for (const [i, def] of (manifest.connectors ?? []).entries()) {\n // An unlisted category renders NO badge rather than a wrong one, so the\n // mistake is invisible in a screenshot. Caught here instead.\n if (def.category !== undefined && !isConnectorCategory(def.category)) {\n fail(\n scope,\n `connectors[${i}].category \"${def.category}\" is not a catalogue category — ` +\n `use one of ${CONNECTOR_CATEGORIES.join(', ')}, taken from the catalogue row with this connector's slug.`,\n )\n }\n for (const pattern of def.subscribesTo ?? []) {\n if (!nonEmptyString(pattern)) fail(scope, `connectors[${i}].subscribesTo must hold non-empty patterns`)\n // Only a trailing star is honoured; see eventKeyMatches.\n if (pattern.includes('*') && !pattern.endsWith('*')) {\n fail(scope, `connectors[${i}].subscribesTo \"${pattern}\" — \"*\" is only honoured at the end`)\n }\n }\n\n assertConnectorPermissions(scope, `connectors[${i}]`, def)\n // The request plane's two fields are required THERE and meaningless\n // elsewhere. Checked at the manifest so a connector cannot reach a buyer\n // with an undeclared budget — the failure would otherwise be a spinner.\n if ((def.planes ?? []).includes('request')) {\n try {\n requestPlaneSpec(def)\n } catch (error) {\n fail(scope, `connectors[${i}] ${error instanceof Error ? error.message : String(error)}`)\n }\n } else if (def.latencyBudgetMs !== undefined || def.onFailure !== undefined) {\n fail(\n scope,\n `connectors[${i}] declares latencyBudgetMs/onFailure but is not on the request plane — ` +\n `nothing enforces them, so they read as a guarantee that does not exist.`,\n )\n }\n // Authorization vs configuration. Both declarations end up on the same row,\n // and a key in both is a value with two owners: the connect form would write\n // it and the settings form would overwrite it.\n const fieldKeys = new Set((def.fields ?? []).map((f) => f.key))\n const settingKeys = new Set<string>()\n for (const [j, setting] of (def.settings ?? []).entries()) {\n const at = `connectors[${i}].settings[${j}]`\n if (!nonEmptyString(setting?.key)) fail(scope, `${at}.key must be a non-empty string`)\n if (!nonEmptyString(setting?.label)) fail(scope, `${at}.label must be a non-empty string`)\n if (!SETTING_TYPES.has(setting.type)) {\n fail(scope, `${at}.type \"${setting.type}\" is not one of ${[...SETTING_TYPES].join(', ')}`)\n }\n if (settingKeys.has(setting.key)) fail(scope, `${at} duplicates settings key \"${setting.key}\"`)\n settingKeys.add(setting.key)\n if (fieldKeys.has(setting.key)) {\n fail(\n scope,\n `${at}.key \"${setting.key}\" is also a credential field — a key either authorizes the ` +\n `connection (fields) or configures it (settings), never both.`,\n )\n }\n if (setting.type === 'select' || setting.type === 'multi-select') {\n if (!Array.isArray(setting.options) || setting.options.length === 0) {\n fail(scope, `${at} is a ${setting.type} and must declare options — that is what replaces a free-text box`)\n }\n for (const [k, option] of setting.options.entries()) {\n if (!nonEmptyString(option?.value)) fail(scope, `${at}.options[${k}].value must be a non-empty string`)\n if (!nonEmptyString(option?.label)) fail(scope, `${at}.options[${k}].label must be a non-empty string`)\n }\n }\n if (setting.pattern !== undefined) {\n if (setting.type !== 'text') fail(scope, `${at}.pattern only applies to a text setting`)\n try {\n new RegExp(setting.pattern)\n } catch {\n fail(scope, `${at}.pattern is not a valid regular expression`)\n }\n // A refusal with no sentence is a form that says no and not why.\n if (!nonEmptyString(setting.patternHint)) fail(scope, `${at} declares a pattern, so it must declare patternHint`)\n }\n }\n // Declared settings nobody can read or write are a screen that renders empty.\n if (settingKeys.size > 0) {\n if (typeof def.getSettings !== 'function') fail(scope, `connectors[${i}] declares settings but no getSettings()`)\n if (typeof def.saveSettings !== 'function') fail(scope, `connectors[${i}] declares settings but no saveSettings()`)\n }\n\n // \"Acionado em quais momentos\" — a moment on a plane the connector does not\n // have is a promise the code cannot keep.\n const planes = new Set(connectorPlanes(def))\n const momentKeys = new Set<string>()\n for (const [j, moment] of (def.invokedAt ?? []).entries()) {\n const at = `connectors[${i}].invokedAt[${j}]`\n if (!nonEmptyString(moment?.key)) fail(scope, `${at}.key must be a non-empty string`)\n if (!nonEmptyString(moment?.label)) fail(scope, `${at}.label must be a non-empty string`)\n if (momentKeys.has(moment.key)) fail(scope, `${at} duplicates key \"${moment.key}\"`)\n momentKeys.add(moment.key)\n const plane = invocationPlane(moment)\n if (!planes.has(plane)) {\n fail(scope, `${at} is declared on the ${plane} plane, which connectors[${i}].planes does not include`)\n }\n if (moment.trigger !== undefined) {\n if (plane !== 'sync') fail(scope, `${at}.trigger only applies to a sync moment`)\n if (!TRIGGERS.has(moment.trigger)) fail(scope, `${at} has unknown trigger \"${moment.trigger}\"`)\n }\n // A moment that reaches something the connector never asked for is the\n // screen answering \"quando ele age\" with access nobody consented to.\n const declared = new Set((def.permissions ?? []).map((p) => p.resource))\n for (const resource of moment.touches ?? []) {\n if (!declared.has(resource)) {\n fail(\n scope,\n `${at}.touches names \"${resource}\", which connectors[${i}].permissions does not declare — ` +\n `a call site cannot reach what the consent view never showed.`,\n )\n }\n }\n }\n\n for (const [j, auto] of (def.managedAutomations ?? []).entries()) {\n if (!nonEmptyString(auto?.eventKey)) fail(scope, `connectors[${i}].managedAutomations[${j}].eventKey must be a non-empty string`)\n if (!nonEmptyString(auto?.label)) fail(scope, `connectors[${i}].managedAutomations[${j}].label must be a non-empty string`)\n // The screen would promise a reaction the ingress never delivers.\n if (!connectorSubscribes(def, auto.eventKey)) {\n fail(scope, `connectors[${i}].managedAutomations[${j}] fires on \"${auto.eventKey}\", which no subscribesTo pattern covers`)\n }\n }\n }\n\n // A connector brings a ConnectorDefinition, not a pair of tables.\n for (const [i, mig] of (manifest.migrations ?? []).entries()) {\n for (const table of bespokeConnectorTables(mig?.sql)) {\n fail(\n scope,\n `migrations[${i}] (\"${mig?.id ?? '?'}\") creates public.${table} — a connector's own ` +\n `*_integrations / *_sync_log table. Store the connection in plg_connections / ` +\n `plg_sync_runs via createConnectionStore('<connector-id>'): two accounts are two ` +\n `rows separated by instance_key, and connector-specific counters go in stats.`,\n )\n }\n }\n\n // A plugin that contributes nothing mountable is almost always a mistake.\n // (Connector-only addon plugins contribute via `connectors` instead.)\n if (\n manifest.navigation.length === 0 &&\n manifest.routes.length === 0 &&\n (manifest.settings ?? []).length === 0 &&\n (manifest.connectors ?? []).length === 0\n ) {\n fail(scope, 'plugin contributes no navigation, routes, settings, or connectors — it would mount but do nothing')\n }\n}\n\n/**\n * What a connector says it needs — and the four ways that declaration can\n * contradict the ones that already existed.\n *\n * The feature this guards is a consent view. Its whole value is that the list it\n * shows is the list, so every way of ending up with two lists is refused here:\n *\n * 1. an action that does not exist for the resource kind (`listen` on a\n * record type, `write` on an event) — a word the reader would have to guess at;\n * 2. a `data` permission naming a resource the legacy `entities` never listed,\n * or an entity with no permission — the \"writes to an entity it never\n * listed\" case, in both directions;\n * 3. a `listen` permission the legacy `subscribesTo` does not name, or a\n * `subscribesTo` pattern no permission explains — the connector would be\n * delivered facts the consent view never showed, or shown facts the ingress\n * filters out;\n * 4. two permissions for the same resource — two rows, two reasons, and no\n * answer to which one the tenant agreed to.\n *\n * Rules 2 and 3 only bite when BOTH declarations are present. A connector built\n * against an older core declares only the legacy fields and is unaffected; a\n * connector written today declares only `permissions` and both are derived from\n * it. What is refused is saying both things and saying them differently.\n */\nfunction assertConnectorPermissions(\n scope: string,\n path: string,\n def: { permissions?: ConnectorPermission[]; entities?: string[]; subscribesTo?: string[] },\n): void {\n const permissions = def.permissions\n if (permissions === undefined) return\n if (!Array.isArray(permissions)) fail(scope, `${path}.permissions must be an array`)\n\n const seen = new Set<string>()\n for (const [j, permission] of permissions.entries()) {\n const at = `${path}.permissions[${j}]`\n if (permission?.kind !== 'data' && permission?.kind !== 'event') {\n fail(scope, `${at}.kind must be \"data\" or \"event\"`)\n }\n if (!nonEmptyString(permission.resource)) fail(scope, `${at}.resource must be a non-empty string`)\n // The reason is the only part a tenant can actually judge; a blank one turns\n // the screen back into the schema dump it exists to replace.\n if (!nonEmptyString(permission.reason)) {\n fail(scope, `${at} must declare a reason — the sentence the tenant judges before authorizing`)\n }\n if (!Array.isArray(permission.actions) || permission.actions.length === 0) {\n fail(scope, `${at}.actions must name at least one action — a resource with no access is not a permission`)\n }\n const legal = permissionActions(permission.kind)\n for (const action of permission.actions) {\n if (!legal.includes(action)) {\n fail(scope, `${at} asks for \"${action}\" on the ${permission.kind} resource \"${permission.resource}\", which only admits ${legal.join(', ')}`)\n }\n }\n if (isEventPermission(permission) && permission.resource.includes('*') && !permission.resource.endsWith('*')) {\n fail(scope, `${at}.resource \"${permission.resource}\" — \"*\" is only honoured at the end`)\n }\n const key = `${permission.kind}:${permission.resource}`\n if (seen.has(key)) fail(scope, `${at} repeats \"${key}\" — one resource, one row, one reason`)\n seen.add(key)\n }\n\n // (2) data permissions ↔ the legacy entities list.\n if (def.entities !== undefined) {\n const declared = new Set(connectorEntities({ permissions }))\n const legacy = new Set(def.entities)\n for (const entity of declared) {\n if (!legacy.has(entity)) {\n fail(\n scope,\n `${path}.permissions reaches \"${entity}\", which ${path}.entities does not list — ` +\n `the two describe the same access and must name the same set (drop entities; it is derived).`,\n )\n }\n }\n for (const entity of legacy) {\n if (!declared.has(entity)) {\n fail(\n scope,\n `${path}.entities lists \"${entity}\" with no permission saying what it does with it — ` +\n `a record type on the consent view with no read/write is a name, not a declaration.`,\n )\n }\n }\n }\n\n // (3) listen permissions ↔ the legacy subscribesTo list.\n if (def.subscribesTo !== undefined) {\n const declared = new Set(connectorSubscribesTo({ permissions }))\n const legacy = new Set(def.subscribesTo)\n for (const pattern of declared) {\n if (!legacy.has(pattern)) {\n fail(\n scope,\n `${path}.permissions listens to \"${pattern}\", which ${path}.subscribesTo does not — ` +\n `the ingress filters on that list, so the consent view would promise a fact never delivered.`,\n )\n }\n }\n for (const pattern of legacy) {\n if (!declared.has(pattern)) {\n fail(\n scope,\n `${path}.subscribesTo asks for \"${pattern}\" with no listen permission explaining it — ` +\n `the connector would receive a fact the tenant was never shown.`,\n )\n }\n }\n }\n}\n\n/**\n * `CREATE TABLE [IF NOT EXISTS] [schema.]name` where name ends in `_integrations`\n * or `_sync_log` — the pair four connectors each reinvented before\n * `plg_connections` / `plg_sync_runs` existed (FAY-1376). Neither generic table\n * matches, so a connector that stores its connection in them creates nothing.\n *\n * Deliberately duplicated in scripts/check-connector-tables.mjs, which scans the\n * .sql files themselves: that runs in the `contracts` CI job with no install and\n * no build, so it cannot import this. This half catches SQL declared inline on a\n * manifest, which no .sql walk would see. The two are held in agreement by one\n * case table, asserted from both sides — see\n * packages/core/test/integrations/connector-tables.test.ts.\n */\nconst BESPOKE_CONNECTOR_TABLE =\n /\\bcreate\\s+table\\s+(?:if\\s+not\\s+exists\\s+)?(?:[a-z0-9_]+\\s*\\.\\s*)?([a-z0-9_]*(?:_integrations|_sync_log))\\b/gi\n\n/** Table names a CREATE TABLE in this SQL would bring back. Empty = conformant. */\nexport function bespokeConnectorTables(sql: unknown): string[] {\n const text = typeof sql === 'string' ? sql.replace(/\"/g, '') : ''\n const found = new Set<string>()\n for (const m of text.matchAll(BESPOKE_CONNECTOR_TABLE)) found.add(m[1].toLowerCase())\n return [...found]\n}\n\nconst EVENT_ACTIONS = new Set(['created', 'updated', 'deleted'])\nconst FUNCTION_INGRESS = new Set(['fayz', 'none'])\nconst SLUG = /^[a-z0-9][a-z0-9-]*$/\nconst SECRET_NAME = /^[A-Z][A-Z0-9_]*$/\n\nconst SETTING_TYPES = new Set(['text', 'select', 'multi-select', 'toggle'])\nconst AUTH_KINDS = new Set(['oauth', 'api-key', 'mtls'])\nconst DIRECTIONS = new Set(['inbound', 'outbound', 'bidirectional'])\nconst TRIGGERS = new Set(['on-write', 'scheduled', 'manual', 'webhook'])\n\n/**\n * Assert an integration Connector descriptor is well-formed: identity present,\n * a known auth kind, and at least one capability with a valid direction +\n * trigger set. This is the contract a connector must satisfy BEFORE its\n * data-plane (edge function) exists — the TDD anchor for an integration.\n */\nexport function assertConnectorContract(connector: Connector): void {\n const scope = nonEmptyString(connector?.id) ? `connector:${connector.id}` : '<unknown connector>'\n for (const field of ['id', 'provider', 'pluginId'] as const) {\n if (!nonEmptyString(connector?.[field])) fail(scope, `connector.${field} must be a non-empty string`)\n }\n if (!AUTH_KINDS.has(connector.authKind)) fail(scope, `connector.authKind \"${connector.authKind}\" is not one of ${[...AUTH_KINDS].join(', ')}`)\n if (!Array.isArray(connector.capabilities) || connector.capabilities.length === 0) {\n fail(scope, 'connector.capabilities must list at least one capability')\n }\n for (const [i, cap] of connector.capabilities.entries()) {\n if (!nonEmptyString(cap?.entity)) fail(scope, `capabilities[${i}].entity must be a non-empty string`)\n if (!DIRECTIONS.has(cap.direction)) fail(scope, `capabilities[${i}].direction \"${cap.direction}\" is invalid`)\n if (!Array.isArray(cap.triggers) || cap.triggers.length === 0) fail(scope, `capabilities[${i}].triggers must be non-empty`)\n for (const trig of cap.triggers) {\n if (!TRIGGERS.has(trig)) fail(scope, `capabilities[${i}] has unknown trigger \"${trig}\"`)\n }\n }\n}\n"]}