@fayz-ai/core 0.6.6 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-OHRATZZH.cjs → chunk-56GH3WC2.cjs} +2 -2
- package/dist/chunk-56GH3WC2.cjs.map +1 -0
- package/dist/{chunk-EKOH5PRX.js → chunk-BBDNC3FP.js} +2 -2
- package/dist/chunk-BBDNC3FP.js.map +1 -0
- package/dist/{chunk-MTDQDB7M.cjs → chunk-P5OJUH25.cjs} +2 -2
- package/dist/chunk-P5OJUH25.cjs.map +1 -0
- package/dist/{chunk-NE4GLVVT.js → chunk-X5THHG6T.js} +2 -2
- package/dist/chunk-X5THHG6T.js.map +1 -0
- package/dist/index.cjs +141 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +127 -3
- package/dist/index.js.map +1 -1
- package/dist/integrations/index.cjs +2 -2
- package/dist/integrations/index.js +1 -1
- package/dist/phone/index.d.ts +28 -0
- package/dist/phone/index.d.ts.map +1 -0
- package/dist/seo/index.d.ts +27 -0
- package/dist/seo/index.d.ts.map +1 -0
- package/dist/testing/index.cjs +4 -4
- package/dist/testing/index.js +1 -1
- package/dist/types/payment.d.ts +38 -0
- package/dist/types/payment.d.ts.map +1 -0
- package/package.json +5 -2
- package/src/index.ts +11 -0
- package/src/integrations/index.ts +1 -1
- package/src/phone/index.ts +85 -0
- package/src/seo/index.ts +128 -0
- package/src/testing/index.ts +1 -1
- package/src/types/payment.ts +44 -0
- package/dist/chunk-EKOH5PRX.js.map +0 -1
- package/dist/chunk-MTDQDB7M.cjs.map +0 -1
- package/dist/chunk-NE4GLVVT.js.map +0 -1
- package/dist/chunk-OHRATZZH.cjs.map +0 -1
|
@@ -31,5 +31,5 @@ function withAfterHooks(target, methods) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
exports.withAfterHooks = withAfterHooks;
|
|
34
|
-
//# sourceMappingURL=chunk-
|
|
35
|
-
//# sourceMappingURL=chunk-
|
|
34
|
+
//# sourceMappingURL=chunk-56GH3WC2.cjs.map
|
|
35
|
+
//# sourceMappingURL=chunk-56GH3WC2.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/index.ts"],"names":[],"mappings":";;;AAmJO,SAAS,cAAA,CACd,QACA,OAAA,EACG;AACH,EAAA,OAAO,IAAI,MAAM,MAAA,EAAQ;AAAA,IACvB,GAAA,CAAI,GAAA,EAAK,IAAA,EAAM,QAAA,EAAU;AACvB,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,MAAM,QAAQ,CAAA;AAC5C,MAAA,MAAM,IAAA,GAAQ,QAA8G,IAAI,CAAA;AAChI,MAAA,IAAI,OAAO,IAAA,KAAS,UAAA,IAAc,CAAC,MAAM,OAAO,IAAA;AAChD,MAAA,OAAO,IAAI,IAAA,KAAoB;AAC7B,QAAA,MAAM,MAAA,GAAU,IAAA,CAAsC,KAAA,CAAM,GAAA,EAAK,IAAI,CAAA;AACrE,QAAA,IAAI,kBAAkB,OAAA,EAAS;AAC7B,UAAA,OAAO,MAAA,CAAO,IAAA,CAAK,CAAC,KAAA,KAAU;AAC5B,YAAA,IAAI;AAAE,cAAA,KAAK,OAAA,CAAQ,QAAQ,IAAA,CAAK,IAAA,EAAM,KAAK,CAAC,CAAA,CAAE,MAAM,MAAM;AAAA,cAAC,CAAC,CAAA;AAAA,YAAE,CAAA,CAAA,MAAQ;AAAA,YAA6B;AACnG,YAAA,OAAO,KAAA;AAAA,UACT,CAAC,CAAA;AAAA,QACH;AACA,QAAA,IAAI;AAAE,UAAA,KAAK,OAAA,CAAQ,QAAQ,IAAA,CAAK,IAAA,EAAM,MAAM,CAAC,CAAA,CAAE,MAAM,MAAM;AAAA,UAAC,CAAC,CAAA;AAAA,QAAE,CAAA,CAAA,MAAQ;AAAA,QAAa;AACpF,QAAA,OAAO,MAAA;AAAA,MACT,CAAA;AAAA,IACF;AAAA,GACD,CAAA;AACH","file":"chunk-56GH3WC2.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// Integration Connector spine\n// ---------------------------------------------------------------------------\n// An integration is a connector that keeps canonical Fayz data in agreement\n// with an external provider (Google Calendar, open banking, Shopify, …). This\n// module is the thin shared contract both native (SDK) and client-built\n// connectors implement. The heavy lifting (auth, fetch/push, idempotent\n// upserts) runs in the data plane — typically a Supabase Edge Function — while\n// the control plane (a settings tab + this contract) lives in the app/plugin.\n//\n// Design notes live in docs/design/bling-integration-brief.md. Proven precedents:\n// the Fayz runtime OAuth broker (packages/core/src/runtime/oauth.ts) and the\n// bank-statement edge functions in the predecessor app.\nimport type * as React from 'react'\n\n/** How a connector authenticates to its provider. */\nexport type IntegrationAuthKind = 'oauth' | 'api-key' | 'mtls'\n\n/** Which way data flows for a given capability. */\nexport type SyncDirection = 'inbound' | 'outbound' | 'bidirectional'\n\n/** What causes a sync to run. */\nexport type SyncTrigger = 'on-write' | 'scheduled' | 'manual' | 'webhook'\n\n/** One thing a connector can sync (an entity + its direction + triggers). */\nexport interface ConnectorCapability {\n /** Canonical entity synced, e.g. 'booking', 'movement'. */\n entity: string\n direction: SyncDirection\n triggers: SyncTrigger[]\n}\n\n/** The state of a tenant's connection to a provider (one row in a *_integrations table). */\nexport interface ConnectionConfig {\n /** Provider key, e.g. 'google', 'plugbank'. */\n provider: string\n /** Whether the connection is active and should sync. */\n active: boolean\n /** Opaque, provider-specific config (calendar id, account id, cursor, …). Never secrets. */\n settings?: Record<string, unknown>\n /** Last successful sync, ISO timestamp. */\n lastSyncAt?: string\n}\n\n/** Audit record of one sync execution (generalizes *_sync_log / *_sync_runs). */\nexport interface SyncRun {\n id?: string\n provider: string\n direction: SyncDirection\n trigger: SyncTrigger\n status: 'success' | 'partial' | 'error'\n /** Items pulled/pushed and how many were written. */\n fetched?: number\n written?: number\n /** Pagination/incremental cursor advanced by this run. */\n cursor?: string\n error?: string\n startedAt?: string\n finishedAt?: string\n}\n\nexport interface TestConnectionResult {\n ok: boolean\n message?: string\n}\n\n/**\n * A connector's control-plane descriptor. The data-plane verbs (testConnection,\n * sync) are usually thin clients that invoke a Supabase Edge Function — the\n * function holds credentials and does the real work.\n */\nexport interface Connector {\n /** Stable connector id, e.g. 'google-calendar', 'plugbank'. */\n id: string\n /** Provider key matching ConnectionConfig.provider. */\n provider: string\n /** Plugin this connector extends, e.g. 'agenda', 'financial'. */\n pluginId: string\n authKind: IntegrationAuthKind\n capabilities: ConnectorCapability[]\n /** Validate the stored credentials/config without syncing. */\n testConnection?(config: ConnectionConfig): Promise<TestConnectionResult>\n /** Run a sync for the given direction; returns the audit record. */\n sync?(input: { config: ConnectionConfig; direction: SyncDirection; trigger: SyncTrigger }): Promise<SyncRun>\n}\n\n// ---------------------------------------------------------------------------\n// Connector UI contract — how an addon plugin EXTENDS a host plugin's settings\n// ---------------------------------------------------------------------------\n// An addon plugin declares one or more ConnectorDefinitions on its manifest\n// (`connectors: [...]`). The runtime groups them by `hostPluginId`, and the host\n// plugin's settings panel renders them in a unified \"Integrations\" tab — the\n// same connect/credentials experience for every connector. The connector-\n// specific bits (import a statement, sync now, history) live in `ExtraPanel`.\n\n/** A credential input the unified setup form renders for an api-key/mtls connector. */\nexport interface ConnectorField {\n key: string\n label: string\n type: 'text' | 'password'\n placeholder?: string\n}\n\nexport interface ConnectorStatus {\n connected: boolean\n detail?: string\n}\n\n/**\n * UI-facing connector descriptor. Built on the data-plane `Connector` concept\n * (`pluginId` → `hostPluginId`), plus the control-plane hooks the unified\n * Integrations hub calls. Lives in core so `PluginManifest.connectors` can type\n * it; the rendering hub lives in `@fayz-ai/saas`.\n */\nexport interface ConnectorDefinition {\n /** Stable connector id, e.g. 'google-calendar', 'plugbank'. */\n id: string\n /** The plugin this connector extends, e.g. 'financial', 'agenda'. */\n hostPluginId: string\n name: string\n description?: string\n /** Lucide icon name. */\n icon?: string\n authKind: IntegrationAuthKind\n /** Declarative credentials — the unified form renders these (api-key / mtls). */\n fields?: ConnectorField[]\n /** Current connection state for the status badge. */\n getStatus(): Promise<ConnectorStatus>\n /** Validate credentials without persisting (api-key / mtls). */\n testConnection?(values: Record<string, string>): Promise<TestConnectionResult>\n /** Persist the connection (api-key / mtls). */\n saveConnection?(values: Record<string, string>): Promise<void>\n /** Begin an OAuth connect flow — returns the consent URL to redirect to. */\n startOAuth?(redirectTo?: string): Promise<string>\n /** Tear down the connection. */\n disconnect?(): Promise<void>\n /** Optional connector-specific UI below the connect panel (import / sync / history). */\n ExtraPanel?: React.ComponentType\n}\n\n/**\n * Wrap an object's async methods so a handler fires AFTER selected methods\n * resolve — the non-invasive hook for outbound, event-driven sync when there's\n * no app-level event bus. Example: wrap an AgendaDataProvider so that after\n * createBooking/updateBooking/deleteBooking succeed, an external calendar is\n * updated. The handler runs fire-and-forget; its failures never break the call.\n */\nexport function withAfterHooks<T extends object>(\n target: T,\n methods: Partial<Record<keyof T, (args: unknown[], result: unknown) => void | Promise<void>>>,\n): T {\n return new Proxy(target, {\n get(obj, prop, receiver) {\n const orig = Reflect.get(obj, prop, receiver)\n const hook = (methods as Record<string | symbol, ((args: unknown[], result: unknown) => void | Promise<void>) | undefined>)[prop]\n if (typeof orig !== 'function' || !hook) return orig\n return (...args: unknown[]) => {\n const result = (orig as (...a: unknown[]) => unknown).apply(obj, args)\n if (result instanceof Promise) {\n return result.then((value) => {\n try { void Promise.resolve(hook(args, value)).catch(() => {}) } catch { /* never break the call */ }\n return value\n })\n }\n try { void Promise.resolve(hook(args, result)).catch(() => {}) } catch { /* noop */ }\n return result\n }\n },\n })\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/index.ts"],"names":[],"mappings":";AAmJO,SAAS,cAAA,CACd,QACA,OAAA,EACG;AACH,EAAA,OAAO,IAAI,MAAM,MAAA,EAAQ;AAAA,IACvB,GAAA,CAAI,GAAA,EAAK,IAAA,EAAM,QAAA,EAAU;AACvB,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,MAAM,QAAQ,CAAA;AAC5C,MAAA,MAAM,IAAA,GAAQ,QAA8G,IAAI,CAAA;AAChI,MAAA,IAAI,OAAO,IAAA,KAAS,UAAA,IAAc,CAAC,MAAM,OAAO,IAAA;AAChD,MAAA,OAAO,IAAI,IAAA,KAAoB;AAC7B,QAAA,MAAM,MAAA,GAAU,IAAA,CAAsC,KAAA,CAAM,GAAA,EAAK,IAAI,CAAA;AACrE,QAAA,IAAI,kBAAkB,OAAA,EAAS;AAC7B,UAAA,OAAO,MAAA,CAAO,IAAA,CAAK,CAAC,KAAA,KAAU;AAC5B,YAAA,IAAI;AAAE,cAAA,KAAK,OAAA,CAAQ,QAAQ,IAAA,CAAK,IAAA,EAAM,KAAK,CAAC,CAAA,CAAE,MAAM,MAAM;AAAA,cAAC,CAAC,CAAA;AAAA,YAAE,CAAA,CAAA,MAAQ;AAAA,YAA6B;AACnG,YAAA,OAAO,KAAA;AAAA,UACT,CAAC,CAAA;AAAA,QACH;AACA,QAAA,IAAI;AAAE,UAAA,KAAK,OAAA,CAAQ,QAAQ,IAAA,CAAK,IAAA,EAAM,MAAM,CAAC,CAAA,CAAE,MAAM,MAAM;AAAA,UAAC,CAAC,CAAA;AAAA,QAAE,CAAA,CAAA,MAAQ;AAAA,QAAa;AACpF,QAAA,OAAO,MAAA;AAAA,MACT,CAAA;AAAA,IACF;AAAA,GACD,CAAA;AACH","file":"chunk-BBDNC3FP.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Integration Connector spine\n// ---------------------------------------------------------------------------\n// An integration is a connector that keeps canonical Fayz data in agreement\n// with an external provider (Google Calendar, open banking, Shopify, …). This\n// module is the thin shared contract both native (SDK) and client-built\n// connectors implement. The heavy lifting (auth, fetch/push, idempotent\n// upserts) runs in the data plane — typically a Supabase Edge Function — while\n// the control plane (a settings tab + this contract) lives in the app/plugin.\n//\n// Design notes live in docs/design/bling-integration-brief.md. Proven precedents:\n// the Fayz runtime OAuth broker (packages/core/src/runtime/oauth.ts) and the\n// bank-statement edge functions in the predecessor app.\nimport type * as React from 'react'\n\n/** How a connector authenticates to its provider. */\nexport type IntegrationAuthKind = 'oauth' | 'api-key' | 'mtls'\n\n/** Which way data flows for a given capability. */\nexport type SyncDirection = 'inbound' | 'outbound' | 'bidirectional'\n\n/** What causes a sync to run. */\nexport type SyncTrigger = 'on-write' | 'scheduled' | 'manual' | 'webhook'\n\n/** One thing a connector can sync (an entity + its direction + triggers). */\nexport interface ConnectorCapability {\n /** Canonical entity synced, e.g. 'booking', 'movement'. */\n entity: string\n direction: SyncDirection\n triggers: SyncTrigger[]\n}\n\n/** The state of a tenant's connection to a provider (one row in a *_integrations table). */\nexport interface ConnectionConfig {\n /** Provider key, e.g. 'google', 'plugbank'. */\n provider: string\n /** Whether the connection is active and should sync. */\n active: boolean\n /** Opaque, provider-specific config (calendar id, account id, cursor, …). Never secrets. */\n settings?: Record<string, unknown>\n /** Last successful sync, ISO timestamp. */\n lastSyncAt?: string\n}\n\n/** Audit record of one sync execution (generalizes *_sync_log / *_sync_runs). */\nexport interface SyncRun {\n id?: string\n provider: string\n direction: SyncDirection\n trigger: SyncTrigger\n status: 'success' | 'partial' | 'error'\n /** Items pulled/pushed and how many were written. */\n fetched?: number\n written?: number\n /** Pagination/incremental cursor advanced by this run. */\n cursor?: string\n error?: string\n startedAt?: string\n finishedAt?: string\n}\n\nexport interface TestConnectionResult {\n ok: boolean\n message?: string\n}\n\n/**\n * A connector's control-plane descriptor. The data-plane verbs (testConnection,\n * sync) are usually thin clients that invoke a Supabase Edge Function — the\n * function holds credentials and does the real work.\n */\nexport interface Connector {\n /** Stable connector id, e.g. 'google-calendar', 'plugbank'. */\n id: string\n /** Provider key matching ConnectionConfig.provider. */\n provider: string\n /** Plugin this connector extends, e.g. 'agenda', 'financial'. */\n pluginId: string\n authKind: IntegrationAuthKind\n capabilities: ConnectorCapability[]\n /** Validate the stored credentials/config without syncing. */\n testConnection?(config: ConnectionConfig): Promise<TestConnectionResult>\n /** Run a sync for the given direction; returns the audit record. */\n sync?(input: { config: ConnectionConfig; direction: SyncDirection; trigger: SyncTrigger }): Promise<SyncRun>\n}\n\n// ---------------------------------------------------------------------------\n// Connector UI contract — how an addon plugin EXTENDS a host plugin's settings\n// ---------------------------------------------------------------------------\n// An addon plugin declares one or more ConnectorDefinitions on its manifest\n// (`connectors: [...]`). The runtime groups them by `hostPluginId`, and the host\n// plugin's settings panel renders them in a unified \"Integrations\" tab — the\n// same connect/credentials experience for every connector. The connector-\n// specific bits (import a statement, sync now, history) live in `ExtraPanel`.\n\n/** A credential input the unified setup form renders for an api-key/mtls connector. */\nexport interface ConnectorField {\n key: string\n label: string\n type: 'text' | 'password'\n placeholder?: string\n}\n\nexport interface ConnectorStatus {\n connected: boolean\n detail?: string\n}\n\n/**\n * UI-facing connector descriptor. Built on the data-plane `Connector` concept\n * (`pluginId` → `hostPluginId`), plus the control-plane hooks the unified\n * Integrations hub calls. Lives in core so `PluginManifest.connectors` can type\n * it; the rendering hub lives in `@fayz-ai/saas`.\n */\nexport interface ConnectorDefinition {\n /** Stable connector id, e.g. 'google-calendar', 'plugbank'. */\n id: string\n /** The plugin this connector extends, e.g. 'financial', 'agenda'. */\n hostPluginId: string\n name: string\n description?: string\n /** Lucide icon name. */\n icon?: string\n authKind: IntegrationAuthKind\n /** Declarative credentials — the unified form renders these (api-key / mtls). */\n fields?: ConnectorField[]\n /** Current connection state for the status badge. */\n getStatus(): Promise<ConnectorStatus>\n /** Validate credentials without persisting (api-key / mtls). */\n testConnection?(values: Record<string, string>): Promise<TestConnectionResult>\n /** Persist the connection (api-key / mtls). */\n saveConnection?(values: Record<string, string>): Promise<void>\n /** Begin an OAuth connect flow — returns the consent URL to redirect to. */\n startOAuth?(redirectTo?: string): Promise<string>\n /** Tear down the connection. */\n disconnect?(): Promise<void>\n /** Optional connector-specific UI below the connect panel (import / sync / history). */\n ExtraPanel?: React.ComponentType\n}\n\n/**\n * Wrap an object's async methods so a handler fires AFTER selected methods\n * resolve — the non-invasive hook for outbound, event-driven sync when there's\n * no app-level event bus. Example: wrap an AgendaDataProvider so that after\n * createBooking/updateBooking/deleteBooking succeed, an external calendar is\n * updated. The handler runs fire-and-forget; its failures never break the call.\n */\nexport function withAfterHooks<T extends object>(\n target: T,\n methods: Partial<Record<keyof T, (args: unknown[], result: unknown) => void | Promise<void>>>,\n): T {\n return new Proxy(target, {\n get(obj, prop, receiver) {\n const orig = Reflect.get(obj, prop, receiver)\n const hook = (methods as Record<string | symbol, ((args: unknown[], result: unknown) => void | Promise<void>) | undefined>)[prop]\n if (typeof orig !== 'function' || !hook) return orig\n return (...args: unknown[]) => {\n const result = (orig as (...a: unknown[]) => unknown).apply(obj, args)\n if (result instanceof Promise) {\n return result.then((value) => {\n try { void Promise.resolve(hook(args, value)).catch(() => {}) } catch { /* never break the call */ }\n return value\n })\n }\n try { void Promise.resolve(hook(args, result)).catch(() => {}) } catch { /* noop */ }\n return result\n }\n },\n })\n}\n"]}
|
|
@@ -77,5 +77,5 @@ function assertConnectorContract(connector) {
|
|
|
77
77
|
exports.PluginContractError = PluginContractError;
|
|
78
78
|
exports.assertConnectorContract = assertConnectorContract;
|
|
79
79
|
exports.assertPluginManifestContract = assertPluginManifestContract;
|
|
80
|
-
//# sourceMappingURL=chunk-
|
|
81
|
-
//# sourceMappingURL=chunk-
|
|
80
|
+
//# sourceMappingURL=chunk-P5OJUH25.cjs.map
|
|
81
|
+
//# sourceMappingURL=chunk-P5OJUH25.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing/index.ts"],"names":[],"mappings":"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","file":"chunk-P5OJUH25.cjs","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/PLUGIN-PATTERNS.md → capability anatomy. These throw on the first violation.\nimport type { PluginManifest } from '../types/plugins'\nimport type { Connector } 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 // 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\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"]}
|
|
@@ -73,5 +73,5 @@ function assertConnectorContract(connector) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
export { PluginContractError, assertConnectorContract, assertPluginManifestContract };
|
|
76
|
-
//# sourceMappingURL=chunk-
|
|
77
|
-
//# sourceMappingURL=chunk-
|
|
76
|
+
//# sourceMappingURL=chunk-X5THHG6T.js.map
|
|
77
|
+
//# sourceMappingURL=chunk-X5THHG6T.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing/index.ts"],"names":[],"mappings":"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","file":"chunk-X5THHG6T.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/PLUGIN-PATTERNS.md → capability anatomy. These throw on the first violation.\nimport type { PluginManifest } from '../types/plugins'\nimport type { Connector } 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 // 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\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"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunk56GH3WC2_cjs = require('./chunk-56GH3WC2.cjs');
|
|
4
|
+
var chunkP5OJUH25_cjs = require('./chunk-P5OJUH25.cjs');
|
|
5
5
|
var chunkVFW6KHBA_cjs = require('./chunk-VFW6KHBA.cjs');
|
|
6
6
|
var chunk2NTHNWEH_cjs = require('./chunk-2NTHNWEH.cjs');
|
|
7
7
|
var chunk5X2VX3RQ_cjs = require('./chunk-5X2VX3RQ.cjs');
|
|
@@ -58,6 +58,129 @@ function createSafeDataProvider(makeSupabase, makeMock) {
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// src/phone/index.ts
|
|
62
|
+
function flagOf(iso2) {
|
|
63
|
+
return iso2.toUpperCase().replace(/[^A-Z]/g, "").split("").map((c) => String.fromCodePoint(127462 + c.charCodeAt(0) - 65)).join("");
|
|
64
|
+
}
|
|
65
|
+
var RAW = [
|
|
66
|
+
{ iso2: "BR", name: "Brasil", dial: "+55", mask: "(##) #####-####" },
|
|
67
|
+
{ iso2: "US", name: "Estados Unidos", dial: "+1", mask: "(###) ###-####" },
|
|
68
|
+
{ iso2: "PT", name: "Portugal", dial: "+351", mask: "### ### ###" },
|
|
69
|
+
{ iso2: "AR", name: "Argentina", dial: "+54", mask: "(##) ####-####" },
|
|
70
|
+
{ iso2: "ES", name: "Espanha", dial: "+34", mask: "### ### ###" },
|
|
71
|
+
{ iso2: "MX", name: "M\xE9xico", dial: "+52", mask: "## #### ####" },
|
|
72
|
+
{ iso2: "GB", name: "Reino Unido", dial: "+44", mask: "##### ######" },
|
|
73
|
+
{ iso2: "FR", name: "Fran\xE7a", dial: "+33", mask: "# ## ## ## ##" },
|
|
74
|
+
{ iso2: "DE", name: "Alemanha", dial: "+49", mask: "#### #######" },
|
|
75
|
+
{ iso2: "IT", name: "It\xE1lia", dial: "+39", mask: "### #######" }
|
|
76
|
+
];
|
|
77
|
+
var COUNTRIES = RAW.map((c) => ({ ...c, flag: flagOf(c.iso2) }));
|
|
78
|
+
var DEFAULT_COUNTRY = "BR";
|
|
79
|
+
var BY_ISO = new Map(COUNTRIES.map((c) => [c.iso2, c]));
|
|
80
|
+
function getCountry(iso2) {
|
|
81
|
+
return iso2 && BY_ISO.get(iso2.toUpperCase()) || BY_ISO.get(DEFAULT_COUNTRY);
|
|
82
|
+
}
|
|
83
|
+
function unmaskPhone(value) {
|
|
84
|
+
return (value || "").replace(/\D/g, "");
|
|
85
|
+
}
|
|
86
|
+
function maskPhone(value, mask) {
|
|
87
|
+
const digits = unmaskPhone(value);
|
|
88
|
+
let out = "";
|
|
89
|
+
let di = 0;
|
|
90
|
+
for (const ch of mask) {
|
|
91
|
+
if (di >= digits.length) break;
|
|
92
|
+
if (ch === "#") {
|
|
93
|
+
out += digits[di++];
|
|
94
|
+
} else {
|
|
95
|
+
out += ch;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
function maskDigitCount(mask) {
|
|
101
|
+
let n = 0;
|
|
102
|
+
for (const ch of mask) if (ch === "#") n++;
|
|
103
|
+
return n;
|
|
104
|
+
}
|
|
105
|
+
var MANAGED = "data-fayz-seo";
|
|
106
|
+
function seoOrigin() {
|
|
107
|
+
return typeof window !== "undefined" ? window.location.origin : "";
|
|
108
|
+
}
|
|
109
|
+
function absoluteUrl(path) {
|
|
110
|
+
return `${seoOrigin()}${path.startsWith("/") ? path : `/${path}`}`;
|
|
111
|
+
}
|
|
112
|
+
function upsertMeta(attr, key, content) {
|
|
113
|
+
if (!content) return;
|
|
114
|
+
let el = document.head.querySelector(`meta[${attr}="${key}"]`);
|
|
115
|
+
if (!el) {
|
|
116
|
+
el = document.createElement("meta");
|
|
117
|
+
el.setAttribute(attr, key);
|
|
118
|
+
el.setAttribute(MANAGED, "");
|
|
119
|
+
document.head.appendChild(el);
|
|
120
|
+
}
|
|
121
|
+
el.setAttribute("content", content);
|
|
122
|
+
}
|
|
123
|
+
function upsertLink(rel, href) {
|
|
124
|
+
if (!href) return;
|
|
125
|
+
let el = document.head.querySelector(`link[rel="${rel}"]`);
|
|
126
|
+
if (!el) {
|
|
127
|
+
el = document.createElement("link");
|
|
128
|
+
el.setAttribute("rel", rel);
|
|
129
|
+
el.setAttribute(MANAGED, "");
|
|
130
|
+
document.head.appendChild(el);
|
|
131
|
+
}
|
|
132
|
+
el.setAttribute("href", href);
|
|
133
|
+
}
|
|
134
|
+
function clearManaged() {
|
|
135
|
+
document.head.querySelectorAll(`[${MANAGED}]`).forEach((el) => el.remove());
|
|
136
|
+
}
|
|
137
|
+
function applySeo(config) {
|
|
138
|
+
if (typeof document === "undefined") return;
|
|
139
|
+
clearManaged();
|
|
140
|
+
document.title = config.title;
|
|
141
|
+
upsertMeta("name", "description", config.description ?? "");
|
|
142
|
+
if (config.canonical) upsertLink("canonical", config.canonical);
|
|
143
|
+
upsertMeta("property", "og:title", config.title);
|
|
144
|
+
upsertMeta("property", "og:description", config.description ?? "");
|
|
145
|
+
upsertMeta("property", "og:type", config.type === "article" ? "article" : "website");
|
|
146
|
+
if (config.canonical) upsertMeta("property", "og:url", config.canonical);
|
|
147
|
+
if (config.image) upsertMeta("property", "og:image", config.image);
|
|
148
|
+
if (config.siteName) upsertMeta("property", "og:site_name", config.siteName);
|
|
149
|
+
upsertMeta("name", "twitter:card", config.image ? "summary_large_image" : "summary");
|
|
150
|
+
upsertMeta("name", "twitter:title", config.title);
|
|
151
|
+
upsertMeta("name", "twitter:description", config.description ?? "");
|
|
152
|
+
if (config.image) upsertMeta("name", "twitter:image", config.image);
|
|
153
|
+
for (const obj of config.jsonLd ?? []) {
|
|
154
|
+
const script = document.createElement("script");
|
|
155
|
+
script.type = "application/ld+json";
|
|
156
|
+
script.setAttribute(MANAGED, "");
|
|
157
|
+
script.text = JSON.stringify(obj);
|
|
158
|
+
document.head.appendChild(script);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function useSeo(config) {
|
|
162
|
+
const key = JSON.stringify(config);
|
|
163
|
+
React2.useEffect(() => {
|
|
164
|
+
applySeo(config);
|
|
165
|
+
return () => clearManaged();
|
|
166
|
+
}, [key]);
|
|
167
|
+
}
|
|
168
|
+
function breadcrumbJsonLd(items) {
|
|
169
|
+
return {
|
|
170
|
+
"@context": "https://schema.org",
|
|
171
|
+
"@type": "BreadcrumbList",
|
|
172
|
+
itemListElement: items.map((c, i) => ({
|
|
173
|
+
"@type": "ListItem",
|
|
174
|
+
position: i + 1,
|
|
175
|
+
name: c.name,
|
|
176
|
+
item: c.url
|
|
177
|
+
}))
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function organizationJsonLd(name, extra) {
|
|
181
|
+
return { "@type": "Organization", name, ...extra };
|
|
182
|
+
}
|
|
183
|
+
|
|
61
184
|
// src/lib/format.ts
|
|
62
185
|
var CURRENCY_BY_LOCALE = {
|
|
63
186
|
"pt-BR": "BRL",
|
|
@@ -654,19 +777,19 @@ function routeModule(path) {
|
|
|
654
777
|
|
|
655
778
|
Object.defineProperty(exports, "withAfterHooks", {
|
|
656
779
|
enumerable: true,
|
|
657
|
-
get: function () { return
|
|
780
|
+
get: function () { return chunk56GH3WC2_cjs.withAfterHooks; }
|
|
658
781
|
});
|
|
659
782
|
Object.defineProperty(exports, "PluginContractError", {
|
|
660
783
|
enumerable: true,
|
|
661
|
-
get: function () { return
|
|
784
|
+
get: function () { return chunkP5OJUH25_cjs.PluginContractError; }
|
|
662
785
|
});
|
|
663
786
|
Object.defineProperty(exports, "assertConnectorContract", {
|
|
664
787
|
enumerable: true,
|
|
665
|
-
get: function () { return
|
|
788
|
+
get: function () { return chunkP5OJUH25_cjs.assertConnectorContract; }
|
|
666
789
|
});
|
|
667
790
|
Object.defineProperty(exports, "assertPluginManifestContract", {
|
|
668
791
|
enumerable: true,
|
|
669
|
-
get: function () { return
|
|
792
|
+
get: function () { return chunkP5OJUH25_cjs.assertPluginManifestContract; }
|
|
670
793
|
});
|
|
671
794
|
Object.defineProperty(exports, "clearGlobalCache", {
|
|
672
795
|
enumerable: true,
|
|
@@ -946,9 +1069,14 @@ Object.defineProperty(exports, "createFayzRuntimeClient", {
|
|
|
946
1069
|
});
|
|
947
1070
|
exports.BlockChildren = BlockChildren;
|
|
948
1071
|
exports.BlockRenderer = BlockRenderer;
|
|
1072
|
+
exports.COUNTRIES = COUNTRIES;
|
|
949
1073
|
exports.CURRENT_MANIFEST_VERSION = CURRENT_MANIFEST_VERSION;
|
|
1074
|
+
exports.DEFAULT_COUNTRY = DEFAULT_COUNTRY;
|
|
950
1075
|
exports.WidgetZone = WidgetZone;
|
|
1076
|
+
exports.absoluteUrl = absoluteUrl;
|
|
951
1077
|
exports.appManifestSchema = app_manifest_schema_default;
|
|
1078
|
+
exports.applySeo = applySeo;
|
|
1079
|
+
exports.breadcrumbJsonLd = breadcrumbJsonLd;
|
|
952
1080
|
exports.buildCSV = buildCSV;
|
|
953
1081
|
exports.createEventBus = createEventBus;
|
|
954
1082
|
exports.createSafeDataProvider = createSafeDataProvider;
|
|
@@ -960,19 +1088,26 @@ exports.formatCurrency = formatCurrency;
|
|
|
960
1088
|
exports.formatDate = formatDate;
|
|
961
1089
|
exports.formatDateTime = formatDateTime;
|
|
962
1090
|
exports.getActiveLocale = getActiveLocale;
|
|
1091
|
+
exports.getCountry = getCountry;
|
|
963
1092
|
exports.getDefaultCurrency = getDefaultCurrency;
|
|
1093
|
+
exports.maskDigitCount = maskDigitCount;
|
|
1094
|
+
exports.maskPhone = maskPhone;
|
|
964
1095
|
exports.migrateManifest = migrateManifest;
|
|
965
1096
|
exports.navHistoryBack = navHistoryBack;
|
|
1097
|
+
exports.organizationJsonLd = organizationJsonLd;
|
|
966
1098
|
exports.recordNavigation = recordNavigation;
|
|
967
1099
|
exports.registerManifestMigration = registerManifestMigration;
|
|
968
1100
|
exports.renderApp = renderApp;
|
|
969
1101
|
exports.renderBlocks = renderBlocks;
|
|
970
1102
|
exports.routeModule = routeModule;
|
|
1103
|
+
exports.seoOrigin = seoOrigin;
|
|
971
1104
|
exports.setDefaultCurrency = setDefaultCurrency;
|
|
1105
|
+
exports.unmaskPhone = unmaskPhone;
|
|
972
1106
|
exports.useManifest = useManifest;
|
|
973
1107
|
exports.useNavHistoryStore = useNavHistoryStore;
|
|
974
1108
|
exports.useNavReferrer = useNavReferrer;
|
|
975
1109
|
exports.useOnEvent = useOnEvent;
|
|
1110
|
+
exports.useSeo = useSeo;
|
|
976
1111
|
exports.validateManifest = validateManifest;
|
|
977
1112
|
//# sourceMappingURL=index.cjs.map
|
|
978
1113
|
//# sourceMappingURL=index.cjs.map
|