@fayz-ai/core 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/access/index.js.map +1 -1
- package/dist/{chunk-L4TLMYGC.js → chunk-6RBW2Y5K.js} +3 -3
- package/dist/chunk-6RBW2Y5K.js.map +1 -0
- package/dist/chunk-732GZEUI.js +1592 -0
- package/dist/chunk-732GZEUI.js.map +1 -0
- package/dist/{chunk-X5THHG6T.js → chunk-CPMHCTX3.js} +3 -3
- package/dist/chunk-CPMHCTX3.js.map +1 -0
- package/dist/{chunk-V2MSAUHO.js → chunk-JO7Z2AOE.js} +2 -2
- package/dist/chunk-JO7Z2AOE.js.map +1 -0
- package/dist/{chunk-5RJVUC6J.js → chunk-M27JPX3K.js} +12 -3
- package/dist/chunk-M27JPX3K.js.map +1 -0
- package/dist/chunk-OXQGRJZT.js +125 -0
- package/dist/chunk-OXQGRJZT.js.map +1 -0
- package/dist/data/backend-env.d.ts +38 -0
- package/dist/data/backend-env.d.ts.map +1 -0
- package/dist/data/index.js +1 -1
- package/dist/entity/events.d.ts +14 -0
- package/dist/entity/events.d.ts.map +1 -0
- package/dist/events/envelope.d.ts +31 -0
- package/dist/events/envelope.d.ts.map +1 -0
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/log.d.ts +44 -0
- package/dist/events/log.d.ts.map +1 -0
- package/dist/events/types.d.ts +40 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/i18n/index.d.ts +10 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/index.d.ts +27 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +388 -52
- package/dist/index.js.map +1 -1
- package/dist/integrations/index.js +1 -1
- package/dist/{integrations/index.d.ts → integrations.d.ts} +2 -2
- package/dist/integrations.d.ts.map +1 -0
- package/dist/{address/index.d.ts → lib/address.d.ts} +1 -1
- package/dist/{address/index.d.ts.map → lib/address.d.ts.map} +1 -1
- package/dist/{phone/index.d.ts → lib/phone.d.ts} +1 -1
- package/dist/lib/phone.d.ts.map +1 -0
- package/dist/{seo/index.d.ts → lib/seo.d.ts} +18 -1
- package/dist/lib/seo.d.ts.map +1 -0
- package/dist/{tenant/index.d.ts → lib/tenant.d.ts} +1 -1
- package/dist/lib/tenant.d.ts.map +1 -0
- package/dist/manifest/index.d.ts +1 -1
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/messaging/index.d.ts +3 -0
- package/dist/messaging/index.d.ts.map +1 -0
- package/dist/messaging/registry.d.ts +35 -0
- package/dist/messaging/registry.d.ts.map +1 -0
- package/dist/messaging/types.d.ts +67 -0
- package/dist/messaging/types.d.ts.map +1 -0
- package/dist/plugin/index.js +2 -1
- package/dist/plugin/runtime.d.ts +17 -0
- package/dist/plugin/runtime.d.ts.map +1 -1
- package/dist/registry/block-catalog.d.ts +78 -0
- package/dist/registry/block-catalog.d.ts.map +1 -0
- package/dist/registry/block-constraints.d.ts +64 -0
- package/dist/registry/block-constraints.d.ts.map +1 -0
- package/dist/registry/block-schema.d.ts +69 -0
- package/dist/registry/block-schema.d.ts.map +1 -0
- package/dist/registry/blocks.d.ts +84 -0
- package/dist/registry/blocks.d.ts.map +1 -0
- package/dist/registry/entities.d.ts +153 -0
- package/dist/registry/entities.d.ts.map +1 -0
- package/dist/registry/extension-points.d.ts +117 -0
- package/dist/registry/extension-points.d.ts.map +1 -0
- package/dist/registry/handles.d.ts +41 -0
- package/dist/registry/handles.d.ts.map +1 -0
- package/dist/registry/index.d.ts +41 -41
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/loaders.d.ts +55 -0
- package/dist/registry/loaders.d.ts.map +1 -0
- package/dist/registry/registry-class.d.ts +157 -0
- package/dist/registry/registry-class.d.ts.map +1 -0
- package/dist/registry/schema-check.d.ts +14 -0
- package/dist/registry/schema-check.d.ts.map +1 -0
- package/dist/router/index.d.ts +78 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/{testing/index.d.ts → testing.d.ts} +3 -3
- package/dist/testing.d.ts.map +1 -0
- package/dist/types/analytics.d.ts +196 -0
- package/dist/types/analytics.d.ts.map +1 -0
- package/dist/types/crud.d.ts +22 -2
- package/dist/types/crud.d.ts.map +1 -1
- package/dist/types/plugins.d.ts +55 -1
- package/dist/types/plugins.d.ts.map +1 -1
- package/package.json +6 -18
- package/dist/blocks/index.d.ts +0 -25
- package/dist/blocks/index.d.ts.map +0 -1
- package/dist/chunk-5RJVUC6J.js.map +0 -1
- package/dist/chunk-L4TLMYGC.js.map +0 -1
- package/dist/chunk-V2MSAUHO.js.map +0 -1
- package/dist/chunk-X5THHG6T.js.map +0 -1
- package/dist/chunk-Y2C2FBQP.js +0 -35
- package/dist/chunk-Y2C2FBQP.js.map +0 -1
- package/dist/chunk-YH25Y4FW.js +0 -311
- package/dist/chunk-YH25Y4FW.js.map +0 -1
- package/dist/integrations/index.d.ts.map +0 -1
- package/dist/phone/index.d.ts.map +0 -1
- package/dist/seo/index.d.ts.map +0 -1
- package/dist/tenant/index.d.ts.map +0 -1
- package/dist/testing/index.d.ts.map +0 -1
- package/src/access/denial.ts +0 -33
- package/src/access/engine.test.ts +0 -48
- package/src/access/engine.ts +0 -136
- package/src/access/index.ts +0 -14
- package/src/access/limits.ts +0 -18
- package/src/address/index.ts +0 -188
- package/src/app/render.tsx +0 -69
- package/src/blocks/index.tsx +0 -68
- package/src/data/archetype.ts +0 -255
- package/src/data/bulk.ts +0 -35
- package/src/data/cached.ts +0 -55
- package/src/data/count.test.ts +0 -152
- package/src/data/count.ts +0 -131
- package/src/data/filters.test.ts +0 -70
- package/src/data/filters.ts +0 -90
- package/src/data/index.ts +0 -11
- package/src/data/mock.ts +0 -90
- package/src/data/platform-api.ts +0 -209
- package/src/data/refresh.ts +0 -115
- package/src/data/resolve.ts +0 -126
- package/src/data/supabase.ts +0 -230
- package/src/data/types.ts +0 -50
- package/src/entity/index.ts +0 -2
- package/src/entity/registry.ts +0 -49
- package/src/events/index.tsx +0 -82
- package/src/i18n/index.ts +0 -476
- package/src/i18n/shell-translations.en.ts +0 -875
- package/src/i18n/shell-translations.pt-br.ts +0 -873
- package/src/index.ts +0 -217
- package/src/integrations/index.ts +0 -237
- package/src/lib/cache.ts +0 -118
- package/src/lib/csv.ts +0 -54
- package/src/lib/format.ts +0 -58
- package/src/manifest/app-manifest.schema.json +0 -676
- package/src/manifest/index.ts +0 -518
- package/src/manifest/serialize.ts +0 -52
- package/src/phone/index.ts +0 -85
- package/src/plugin/createSafeDataProvider.ts +0 -30
- package/src/plugin/index.ts +0 -1
- package/src/plugin/runtime.ts +0 -331
- package/src/registry/index.ts +0 -163
- package/src/router/history.ts +0 -86
- package/src/router/index.ts +0 -29
- package/src/runtime/index.ts +0 -15
- package/src/runtime/oauth.ts +0 -219
- package/src/search/engine.ts +0 -559
- package/src/search/index.ts +0 -25
- package/src/search/text.ts +0 -206
- package/src/search/types.ts +0 -75
- package/src/seo/index.ts +0 -128
- package/src/tenant/index.ts +0 -38
- package/src/testing/index.ts +0 -116
- package/src/types/auth.ts +0 -41
- package/src/types/billing.ts +0 -39
- package/src/types/crud.ts +0 -184
- package/src/types/entities.ts +0 -142
- package/src/types/entitlements.ts +0 -45
- package/src/types/i18n.ts +0 -7
- package/src/types/index.ts +0 -11
- package/src/types/org.ts +0 -137
- package/src/types/payment.ts +0 -44
- package/src/types/permissions.ts +0 -32
- package/src/types/plugins.ts +0 -480
- package/src/types/theme.ts +0 -8
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/registry/index.ts","../src/plugin/runtime.ts"],"names":[],"mappings":";;;AAuCO,IAAM,WAAN,MAAkB;AAAA,EAGvB,YAAqB,IAAA,EAAc;AAAd,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAFrB,IAAA,IAAA,CAAiB,OAAA,uBAAc,GAAA,EAA8B;AAAA,EAEzB;AAAA,EAEpC,QAAA,CAAS,EAAA,EAAY,KAAA,EAAU,IAAA,GAAqB,EAAC,EAAS;AAC5D,IAAA,IAAA,CAAK,QAAQ,GAAA,CAAI,EAAA,EAAI,EAAE,EAAA,EAAI,KAAA,EAAO,MAAM,CAAA;AAAA,EAC1C;AAAA,EAEA,IAAI,EAAA,EAA2B;AAC7B,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA,EAAG,KAAA;AAAA,EAC/B;AAAA,EAEA,SAAS,EAAA,EAA0C;AACjD,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AAAA,EAC5B;AAAA,EAEA,IAAI,EAAA,EAAqB;AACvB,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AAAA,EAC5B;AAAA,EAEA,IAAA,GAA2B;AACzB,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,QAAQ,CAAA;AAAA,EACzC;AAAA,EAEA,GAAA,GAAgB;AACd,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,MAAM,CAAA;AAAA,EACvC;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AAAA,EACrB;AACF;AAGO,SAAS,WAAW,EAAA,EAAqB;AAC9C,EAAA,OAAO,EAAA,CAAG,WAAW,SAAS,CAAA;AAChC;AAsCO,IAAM,iBAAA,GAAoB,IAAI,QAAA,CAAuB,WAAW;AAChE,IAAM,aAAA,GAAgB,IAAI,QAAA,CAAuB,OAAO;AACxD,IAAM,YAAA,GAAe,IAAI,QAAA,CAAuB,MAAM;AACtD,IAAM,gBAAA,GAAmB,IAAI,QAAA,CAAuB,UAAU;AAC9D,IAAM,cAAA,GAAiB,IAAI,QAAA,CAA2B,QAAQ;AAE9D,IAAM,cAAA,GAAiB,IAAI,QAAA,CAAc,QAAQ;AAIjD,IAAM,iBAAA,GAAoB,CAAC,EAAA,EAAY,CAAA,EAAiB,SAC7D,iBAAA,CAAkB,QAAA,CAAS,EAAA,EAAI,CAAA,EAAG,IAAI;AACjC,IAAM,YAAA,GAAe,CAAC,EAAA,KAAe,iBAAA,CAAkB,IAAI,EAAE;AAE7D,IAAM,aAAA,GAAgB,CAAC,EAAA,EAAY,CAAA,EAAiB,SACzD,aAAA,CAAc,QAAA,CAAS,EAAA,EAAI,CAAA,EAAG,IAAI;AAC7B,IAAM,QAAA,GAAW,CAAC,EAAA,KAAe,aAAA,CAAc,IAAI,EAAE;AACrD,IAAM,UAAA,GAAa,MAAM,aAAA,CAAc,IAAA;AAEvC,IAAM,YAAA,GAAe,CAAC,EAAA,EAAY,CAAA,EAAiB,SACxD,YAAA,CAAa,QAAA,CAAS,EAAA,EAAI,CAAA,EAAG,IAAI;AAC5B,IAAM,OAAA,GAAU,CAAC,EAAA,KAAe,YAAA,CAAa,IAAI,EAAE;AAEnD,IAAM,gBAAA,GAAmB,CAAC,EAAA,EAAY,CAAA,EAAiB,SAC5D,gBAAA,CAAiB,QAAA,CAAS,EAAA,EAAI,CAAA,EAAG,IAAI;AAChC,IAAM,WAAA,GAAc,CAAC,EAAA,KAAe,gBAAA,CAAiB,IAAI,EAAE;AAE3D,IAAM,cAAA,GAAiB,CAAC,GAAA,EAAuB,IAAA,KACpD,eAAe,QAAA,CAAS,GAAA,CAAI,EAAA,EAAI,GAAA,EAAK,IAAI;AACpC,IAAM,SAAA,GAAY,CAAC,EAAA,KAAe,cAAA,CAAe,IAAI,EAAE;AACvD,IAAM,WAAA,GAAc,MAAM,cAAA,CAAe,IAAA;AAGzC,IAAM,cAAA,GAAiB,CAAC,EAAA,EAAY,QAAA,EAAe,SACxD,cAAA,CAAe,QAAA,CAAS,EAAA,EAAI,QAAA,EAAU,IAAI;AACrC,IAAM,SAAA,GAAY,CAAC,EAAA,KAAe,cAAA,CAAe,IAAI,EAAE;AACvD,IAAM,WAAA,GAAc,MAAM,cAAA,CAAe,IAAA;AAQzC,IAAM,qBAAA,GAAwB,IAAI,QAAA,CAAwB,gBAAgB;AAC1E,IAAM,qBAAA,GAAwB,CAAC,EAAA,EAAY,OAAA,EAAwB,SACxE,qBAAA,CAAsB,QAAA,CAAS,EAAA,EAAI,OAAA,EAAS,IAAI;AAC3C,IAAM,gBAAA,GAAmB,CAAC,EAAA,KAAe,qBAAA,CAAsB,IAAI,EAAE;AACrE,IAAM,mBAAA,GAAsB,MAAM,qBAAA,CAAsB,IAAA;ACtIxD,IAAM,kBAAA,GAAqB;AAI3B,SAAS,uBACd,GAAA,EAC0C;AAC1C,EAAA,IAAI,GAAA,CAAI,SAAA,EAAW,OAAO,GAAA,CAAI,SAAA;AAC9B,EAAA,IAAI,GAAA,CAAI,WAAA,EAAa,OAAO,YAAA,CAAa,IAAI,WAAW,CAAA;AACxD,EAAA,OAAO,MAAA;AACT;AASA,IAAM,aAAA,GAAsC;AAAA,EAC1C,MAAA,EAAQ,IAAA;AAAA,EACR,IAAA,EAAM,IAAA;AAAA,EACN,WAAA,EAAa,GAAA;AAAA,EACb,WAAA,EAAa,GAAA;AAAA,EACb,MAAA,EAAQ;AACV,CAAA;AAEA,SAAS,QAAQ,KAAA,EAAuB;AACtC,EAAA,OAAO,KAAA,CAAM,aAAY,CAAE,OAAA,CAAQ,eAAe,GAAG,CAAA,CAAE,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA;AAC7E;AAEA,SAAS,mBAAA,CAAoB,SAAiB,WAAA,EAA8B;AAC1E,EAAA,IAAI,OAAA,KAAY,aAAa,OAAO,IAAA;AACpC,EAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA,EAAG;AAC1B,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAChC,IAAA,OAAO,gBAAgB,IAAA,IAAQ,WAAA,CAAY,UAAA,CAAW,CAAA,EAAG,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,EAClE;AACA,EAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAAG,OAAO,WAAA,CAAY,UAAA,CAAW,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA;AAC7E,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,eAAA,CAAgB,QAA8B,OAAA,EAAwC;AAC7F,EAAA,IAAI,MAAA,CAAO,UAAA,IAAc,OAAA,CAAQ,aAAA,IAAiB,CAAC,QAAQ,aAAA,CAAc,MAAA,CAAO,UAAU,CAAA,EAAG,OAAO,KAAA;AACpG,EAAA,MAAM,aAAiD,MAAA,CAAO,UAAA;AAC9D,EAAA,IAAI,CAAC,YAAY,OAAO,IAAA;AAExB,EAAA,IAAI,UAAA,CAAW,WAAW,CAAC,UAAA,CAAW,QAAQ,QAAA,CAAS,OAAA,CAAQ,MAAM,CAAA,EAAG,OAAO,KAAA;AAC/E,EAAA,IAAI,UAAA,CAAW,KAAA,IAAS,OAAA,CAAQ,IAAA,EAAM,IAAA,IAAQ,CAAC,UAAA,CAAW,KAAA,CAAM,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,IAAI,GAAG,OAAO,KAAA;AACpG,EAAA,IAAI,WAAW,KAAA,IAAS,CAAC,OAAA,CAAQ,IAAA,EAAM,MAAM,OAAO,KAAA;AACpD,EAAA,IAAI,UAAA,CAAW,KAAA,IAAS,OAAA,CAAQ,MAAA,EAAQ,IAAA,IAAQ,CAAC,UAAA,CAAW,KAAA,CAAM,QAAA,CAAS,OAAA,CAAQ,MAAA,CAAO,IAAI,GAAG,OAAO,KAAA;AACxG,EAAA,IAAI,WAAW,KAAA,IAAS,CAAC,OAAA,CAAQ,MAAA,EAAQ,MAAM,OAAO,KAAA;AACtD,EAAA,IAAI,UAAA,CAAW,MAAA,IAAU,CAAC,UAAA,CAAW,OAAO,IAAA,CAAK,CAAC,CAAA,KAAM,mBAAA,CAAoB,CAAA,EAAG,OAAA,CAAQ,WAAW,CAAC,GAAG,OAAO,KAAA;AAC7G,EAAA,IAAI,UAAA,CAAW,aAAA,EAAe,IAAA,CAAK,CAAC,CAAA,KAAM,mBAAA,CAAoB,CAAA,EAAG,OAAA,CAAQ,WAAW,CAAC,CAAA,EAAG,OAAO,KAAA;AAC/F,EAAA,IAAI,UAAA,CAAW,aAAa,MAAA,EAAQ;AAClC,IAAA,IAAI,CAAC,OAAA,CAAQ,aAAA,EAAe,OAAO,KAAA;AACnC,IAAA,IAAI,CAAC,UAAA,CAAW,WAAA,CAAY,KAAA,CAAM,CAAC,GAAA,KAAQ,OAAA,CAAQ,aAAA,GAAgB,GAAG,CAAC,CAAA,EAAG,OAAO,KAAA;AAAA,EACnF;AACA,EAAA,IAAI,WAAW,IAAA,IAAQ,CAAC,WAAW,IAAA,CAAK,OAAO,GAAG,OAAO,KAAA;AACzD,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,sBAAsB,MAAA,EAA6C;AAC1E,EAAA,OAAA,CAAQ,OAAO,QAAA,IAAY,IAAI,GAAA,CAAI,CAAC,OAAO,KAAA,MAAW;AAAA,IACpD,GAAG,KAAA;AAAA,IACH,QAAA,EAAU,KAAA,CAAM,QAAA,IAAY,MAAA,CAAO,EAAA;AAAA,IACnC,KAAA,EAAO,MAAM,KAAA,IAAS,KAAA;AAAA,IACtB,EAAA,EAAI,KAAA,CAAM,EAAA,IAAM,CAAA,EAAG,MAAA,CAAO,EAAE,CAAA,CAAA,EAAI,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,GACtD,CAAE,CAAA;AACJ;AAEA,SAAS,kBAAA,CAAmB,UAAgC,aAAA,EAA8B;AACxF,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,SAAS,EAAC;AAAA,IACV,eAAe,EAAC;AAAA,IAChB,QAAQ,EAAC;AAAA,IACT,YAAY,EAAC;AAAA,IACb,cAAc,EAAC;AAAA,IACf,SAAS,EAAC;AAAA,IACV,kBAAkB,EAAC;AAAA,IACnB,cAAc,EAAC;AAAA,IACf,SAAS,EAAC;AAAA,IACV,UAAA,sBAAgB,GAAA,EAAI;AAAA,IACpB,gBAAA,sBAAsB,GAAA,EAAI;AAAA,IAC1B,gBAAgB,EAAC;AAAA,IACjB,cAAc,EAAC;AAAA,IACf,QAAQ;AAAC,GACX;AACF;AAEO,SAAS,aAAuC,MAAA,EAAc;AACnE,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,oBAAA,CAAqB;AAAA,EACnC,UAAU,EAAC;AAAA,EACX,gBAAgB,EAAC;AAAA,EACjB,iBAAA;AAAA,EACA;AACF,CAAA,EAA+C;AAC7C,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,mBAAmB,OAAO,CAAA;AAE3D,EAAA,MAAM,SAA+B,EAAC;AACtC,EAAA,MAAM,iBAAA,uBAAwB,GAAA,EAA4B;AAE1D,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA,EAAG;AACpC,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,kBAAA,EAAoB,QAAA,EAAU,MAAA,CAAO,EAAA,EAAI,OAAA,EAAS,CAAA,QAAA,EAAW,MAAA,CAAO,EAAE,CAAA,4BAAA,CAAA,EAAgC,CAAA;AAC1H,MAAA;AAAA,IACF;AACA,IAAA,IAAI,MAAA,CAAO,UAAA,IAAc,IAAA,IAAQ,MAAA,CAAO,aAAa,kBAAA,EAAoB;AACvE,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,0BAAA;AAAA,QACN,UAAU,MAAA,CAAO,EAAA;AAAA,QACjB,OAAA,EAAS,WAAW,MAAA,CAAO,EAAE,0BAA0B,MAAA,CAAO,UAAU,gCAAgC,kBAAkB,CAAA,wBAAA;AAAA,OAC3H,CAAA;AACD,MAAA;AAAA,IACF;AACA,IAAA,iBAAA,CAAkB,GAAA,CAAI,MAAA,CAAO,EAAA,EAAI,MAAM,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAiC;AACtD,EAAA,KAAA,MAAW,KAAK,aAAA,EAAe,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,UAAU,CAAC,CAAA;AACzD,EAAA,MAAM,kBAAA,GAAqB,iBAAA,IAAqB,aAAA,CAAc,MAAA,GAAS,CAAA;AAEvE,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAY;AAClC,EAAA,MAAM,gBAAA,uBAAuB,GAAA,EAAwD;AAErF,EAAA,KAAA,MAAW,MAAA,IAAU,iBAAA,CAAkB,MAAA,EAAO,EAAG;AAC/C,IAAA,MAAM,OAAA,GAAU,QAAA,CAAS,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA;AACtC,IAAA,IAAI,OAAA,EAAS,WAAW,QAAA,EAAU;AAChC,MAAA,SAAA,CAAU,GAAA,CAAI,OAAO,EAAE,CAAA;AACvB,MAAA,gBAAA,CAAiB,GAAA,CAAI,MAAA,CAAO,EAAA,EAAI,QAAQ,CAAA;AACxC,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,cAAA,KAAmB,IAAA,IAAS,CAAC,kBAAA,IAAsB,MAAA,CAAO,mBAAmB,KAAA,EAAQ;AAC9F,MAAA,SAAA,CAAU,GAAA,CAAI,OAAO,EAAE,CAAA;AACvB,MAAA,gBAAA,CAAiB,GAAA,CAAI,MAAA,CAAO,EAAA,EAAI,SAAS,CAAA;AAAA,IAC3C;AAAA,EACF;AAEA,EAAA,MAAM,aAAuB,EAAC;AAC9B,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAY;AACjC,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAEhC,EAAA,SAAS,KAAA,CAAM,QAAA,EAAkB,QAAA,GAAqB,EAAC,EAAS;AAC9D,IAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA,EAAG;AAC3B,IAAA,MAAM,MAAA,GAAS,iBAAA,CAAkB,GAAA,CAAI,QAAQ,CAAA;AAC7C,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,IAAI,QAAA,CAAS,GAAA,CAAI,QAAQ,CAAA,EAAG;AAC1B,MAAA,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,qBAAA,EAAuB,QAAA,EAAU,SAAS,CAAA,qBAAA,EAAwB,CAAC,GAAG,QAAA,EAAU,QAAQ,CAAA,CAAE,IAAA,CAAK,MAAM,CAAC,KAAK,CAAA;AAC/H,MAAA;AAAA,IACF;AACA,IAAA,QAAA,CAAS,IAAI,QAAQ,CAAA;AACrB,IAAA,KAAA,MAAW,KAAA,IAAS,MAAA,CAAO,YAAA,IAAgB,EAAC,EAAG;AAC7C,MAAA,IAAI,CAAC,iBAAA,CAAkB,GAAA,CAAI,KAAK,CAAA,EAAG;AACjC,QAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,oBAAA,EAAsB,UAAU,YAAA,EAAc,KAAA,EAAO,OAAA,EAAS,CAAA,QAAA,EAAW,MAAA,CAAO,EAAE,CAAA,6BAAA,EAAgC,KAAK,MAAM,CAAA;AACjJ,QAAA;AAAA,MACF;AACA,MAAA,IAAI,SAAA,CAAU,IAAI,QAAQ,CAAA,IAAK,CAAC,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA,EAAG;AACpD,QAAA,SAAA,CAAU,IAAI,KAAK,CAAA;AACnB,QAAA,gBAAA,CAAiB,GAAA,CAAI,OAAO,YAAY,CAAA;AAAA,MAC1C;AACA,MAAA,KAAA,CAAM,KAAA,EAAO,CAAC,GAAG,QAAA,EAAU,QAAQ,CAAC,CAAA;AAAA,IACtC;AACA,IAAA,QAAA,CAAS,OAAO,QAAQ,CAAA;AACxB,IAAA,OAAA,CAAQ,IAAI,QAAQ,CAAA;AACpB,IAAA,UAAA,CAAW,KAAK,QAAQ,CAAA;AAAA,EAC1B;AAEA,EAAA,KAAA,MAAW,EAAA,IAAM,iBAAA,CAAkB,IAAA,EAAK,QAAS,EAAE,CAAA;AAEnD,EAAA,MAAM,YAAA,uBAAmB,GAAA,EAAoC;AAE7D,EAAA,KAAA,MAAW,YAAY,UAAA,EAAY;AACjC,IAAA,MAAM,MAAA,GAAS,iBAAA,CAAkB,GAAA,CAAI,QAAQ,CAAA;AAC7C,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,MAAM,OAAA,GAAU,QAAA,CAAS,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA;AACtC,IAAA,MAAM,OAAA,GAAA,CAAW,MAAA,CAAO,YAAA,IAAgB,EAAC,EAAG,MAAA,CAAO,CAAC,EAAA,KAAO,CAAC,iBAAA,CAAkB,GAAA,CAAI,EAAE,CAAC,CAAA;AACrF,IAAA,MAAM,aAAa,CAAC,MAAA,CAAO,cAAc,MAAA,CAAO,UAAA,KAAe,QAAQ,MAAA,EAAQ,UAAA;AAC/E,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,mBAAA,EAAqB,UAAU,MAAA,CAAO,EAAA,EAAI,OAAA,EAAS,CAAA,QAAA,EAAW,OAAO,EAAE,CAAA,qBAAA,EAAwB,MAAA,CAAO,UAAU,MAAM,CAAA;AAAA,IAC5I;AACA,IAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA,IAAK,UAAA;AAClD,IAAA,MAAM,SAAA,GAAA,CAAa,MAAA,CAAO,YAAA,IAAgB,EAAC,EAAG,KAAA,CAAM,CAAC,EAAA,KAAO,YAAA,CAAa,GAAA,CAAI,EAAE,CAAA,EAAG,QAAQ,CAAA;AAC1F,IAAA,MAAM,kBAAA,GAAqB,OAAA,EAAS,MAAA,KAAW,UAAA,IAAc,SAAS,MAAA,KAAW,SAAA;AACjF,IAAA,MAAM,cAAA,GAAiB,WAAW,YAAA,GAAe,IAAA,GAAO,UAAU,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA,IAAK,CAAC,kBAAA;AACrF,IAAA,MAAM,QAAA,GAAW,cAAA,IAAkB,UAAA,IAAc,OAAA,CAAQ,WAAW,CAAA,IAAK,SAAA;AAEzE,IAAA,YAAA,CAAa,GAAA,CAAI,OAAO,EAAA,EAAI;AAAA,MAC1B,GAAG,MAAA;AAAA,MACH,MAAA,EAAQ,QAAA,GAAW,QAAA,GAAY,OAAA,EAAS,MAAA,IAAU,UAAA;AAAA,MAClD,QAAA;AAAA,MACA,gBAAA,EAAkB,WAAW,MAAA,GAAS,UAAA;AAAA,MACtC,MAAA,EAAQ,OAAA,EAAS,MAAA,IAAU,EAAC;AAAA,MAC5B,mBAAA,EAAqB,OAAA;AAAA,MACrB,YAAA,EAAc,sBAAsB,MAAM,CAAA;AAAA,MAC1C,OAAA,EAAS,MAAA,CAAO,OAAA,IAAW,EAAC;AAAA,MAC5B,kBAAA,EAAoB,MAAA,CAAO,UAAA,IAAc,EAAC;AAAA,MAC1C,eAAA,EAAiB,MAAA,CAAO,OAAA,IAAW;AAAC,KACrC,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,eAAA,GAAkB,UAAA,CACrB,GAAA,CAAI,CAAC,OAAO,YAAA,CAAa,GAAA,CAAI,EAAE,CAAC,EAChC,MAAA,CAAO,CAAC,CAAA,KAAmC,OAAA,CAAQ,CAAC,CAAC,CAAA;AAExD,EAAA,MAAM,gBAAgB,eAAA,CAAgB,MAAA,CAAO,CAAC,CAAA,KAAM,EAAE,QAAQ,CAAA;AAC9D,EAAA,MAAM,SAA+B,EAAC;AACtC,EAAA,MAAM,aAAsC,EAAC;AAC7C,EAAA,MAAM,eAAoC,EAAC;AAC3C,EAAA,MAAM,UAAkC,EAAC;AACzC,EAAA,MAAM,mBAA8C,EAAC;AACrD,EAAA,MAAM,eAAmC,EAAC;AAC1C,EAAA,MAAM,UAA0B,EAAC;AACjC,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAiC;AACxD,EAAA,MAAM,gBAAA,uBAAuB,GAAA,EAAmC;AAChE,EAAA,MAAM,iBAAuC,EAAC;AAC9C,EAAA,MAAM,eAAmC,EAAC;AAE1C,EAAA,KAAA,MAAW,UAAU,aAAA,EAAe;AAClC,IAAA,MAAA,CAAO,IAAA,CAAK,GAAG,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAG,MAAA,EAAO,CAAE,CAAC,CAAA;AAC3D,IAAA,UAAA,CAAW,KAAK,GAAG,MAAA,CAAO,WAAW,GAAA,CAAI,CAAC,OAAO,CAAA,MAAO;AAAA,MACtD,GAAG,KAAA;AAAA,MACH,EAAA,EAAI,KAAA,CAAM,EAAA,IAAM,CAAA,EAAG,MAAA,CAAO,EAAE,CAAA,CAAA,EAAI,KAAA,CAAM,KAAK,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA;AAAA,MAChD,IAAA,EAAM,KAAA,CAAM,IAAA,IAAQ,MAAA,CAAO;AAAA,MAC3B,CAAC,CAAA;AACH,IAAA,YAAA,CAAa,IAAA,CAAK,GAAG,MAAA,CAAO,YAAY,CAAA;AACxC,IAAA,YAAA,CAAa,IAAA,CAAK,GAAI,MAAA,CAAO,YAAA,IAAgB,EAAG,CAAA;AAChD,IAAA,OAAA,CAAQ,IAAA,CAAK,GAAG,MAAA,CAAO,eAAe,CAAA;AACtC,IAAA,IAAI,MAAA,CAAO,mBAAmB,MAAA,GAAS,CAAA,aAAc,GAAA,CAAI,MAAA,CAAO,EAAA,EAAI,MAAA,CAAO,kBAAkB,CAAA;AAE7F,IAAA,KAAA,MAAW,SAAA,IAAa,MAAA,CAAO,UAAA,IAAc,EAAC,EAAG;AAC/C,MAAA,MAAM,OAAO,gBAAA,CAAiB,GAAA,CAAI,SAAA,CAAU,YAAY,KAAK,EAAC;AAC9D,MAAA,IAAA,CAAK,KAAK,SAAS,CAAA;AACnB,MAAA,gBAAA,CAAiB,GAAA,CAAI,SAAA,CAAU,YAAA,EAAc,IAAI,CAAA;AAAA,IACnD;AACA,IAAA,IAAI,OAAO,gBAAA,EAAkB,cAAA,CAAe,IAAA,CAAK,GAAG,OAAO,gBAAgB,CAAA;AAC3E,IAAA,IAAI,OAAO,cAAA,EAAgB,YAAA,CAAa,IAAA,CAAK,GAAG,OAAO,cAAc,CAAA;AACrE,IAAA,OAAA,CAAQ,KAAK,GAAG,MAAA,CAAO,QAAQ,GAAA,CAAI,CAAC,GAAG,CAAA,MAAO;AAAA,MAC5C,GAAG,CAAA;AAAA,MACH,KAAA,EAAO,EAAE,KAAA,IAAS,CAAA;AAAA,MAClB,MAAA,EAAQ,EAAE,GAAG,MAAA,CAAO,QAAQ,GAAI,CAAA,CAAE,KAAA,IAAS,EAAC,EAAG;AAAA,MAC/C;AAAA,MACA,CAAC,CAAA;AACH,IAAA,gBAAA,CAAiB,IAAA,CAAK,IAAI,MAAA,CAAO,gBAAA,IAAoB,EAAC,EAAG,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,MAAO;AAAA,MACtE,GAAG,CAAA;AAAA,MACH,MAAA,EAAQ,CAAA,CAAE,MAAA,IAAU,MAAA,CAAO,EAAA;AAAA,MAC3B,KAAA,EAAO,EAAE,YAAA,IAAgB,CAAA;AAAA,MACzB;AAAA,MACA,CAAC,CAAA;AAAA,EACL;AAEA,EAAA,UAAA,CAAW,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM;AACxB,IAAA,MAAM,QAAQ,EAAE,IAAA,EAAM,GAAG,SAAA,EAAW,CAAA,EAAG,UAAU,CAAA,EAAE;AACnD,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,CAAE,OAAO,CAAA,IAAK,EAAA,KAAO,KAAA,CAAM,CAAA,CAAE,OAAO,CAAA,IAAK,EAAA,CAAA,IAAO,CAAA,CAAE,QAAA,GAAW,CAAA,CAAE,QAAA;AAAA,EAC/E,CAAC,CAAA;AACD,EAAA,YAAA,CAAa,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAA,CAAO,EAAE,KAAA,IAAS,CAAA,KAAM,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE,CAAA;AAC3D,EAAA,OAAA,CAAQ,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,SAAS,CAAA,CAAE,IAAA,GAAO,CAAA,CAAE,IAAA,CAAK,cAAc,CAAA,CAAE,IAAI,IAAI,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAK,CAAA;AAC3F,EAAA,gBAAA,CAAiB,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAK,CAAA;AAEjD,EAAA,OAAO,EAAE,OAAA,EAAS,OAAA,EAAS,eAAA,EAAiB,aAAA,EAAe,QAAQ,UAAA,EAAY,YAAA,EAAc,OAAA,EAAS,gBAAA,EAAkB,cAAc,OAAA,EAAS,MAAA,EAAQ,UAAA,EAAY,gBAAA,EAAkB,gBAAgB,YAAA,EAAa;AACpN;AAEO,SAAS,iBAAA,CACd,OAAA,EACA,IAAA,EACA,gBAAA,EACwB;AACxB,EAAA,MAAM,MAAM,EAAE,GAAG,OAAA,CAAQ,OAAA,EAAS,GAAG,gBAAA,EAAiB;AACtD,EAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,IAAA,IAAQ,eAAA,CAAgB,CAAA,EAAG,GAAG,CAAC,CAAA;AACjF;AAEO,SAAS,mBAAA,CACd,SACA,OAAA,EAC2B;AAC3B,EAAA,MAAM,MAAM,EAAE,GAAG,QAAQ,OAAA,EAAS,GAAG,QAAQ,gBAAA,EAAiB;AAC9D,EAAA,OAAO,OAAA,CAAQ,gBAAA,CAAiB,MAAA,CAAO,CAAC,CAAA,KAAM;AAC5C,IAAA,MAAM,QAAA,GAAW,CAAA,CAAE,QAAA,IAAY,CAAC,QAAQ,aAAa,CAAA;AACrD,IAAA,IAAI,CAAC,QAAA,CAAS,QAAA,CAAS,OAAA,CAAQ,OAAO,GAAG,OAAO,KAAA;AAChD,IAAA,IAAI,QAAQ,MAAA,IAAU,CAAA,CAAE,MAAA,KAAW,OAAA,CAAQ,QAAQ,OAAO,KAAA;AAC1D,IAAA,IAAI,CAAA,CAAE,UAAA,IAAc,GAAA,CAAI,MAAA,EAAQ,UAAA,IAAc,EAAE,UAAA,KAAe,GAAA,CAAI,MAAA,CAAO,UAAA,EAAY,OAAO,KAAA;AAC7F,IAAA,IAAI,CAAA,CAAE,UAAA,IAAc,GAAA,CAAI,aAAA,IAAiB,CAAC,IAAI,aAAA,CAAc,CAAA,CAAE,UAAU,CAAA,EAAG,OAAO,KAAA;AAClF,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AACH;AAEA,IAAM,oBAAA,GAA6B,oBAAoC,IAAI,CAAA;AACpE,IAAM,wBAAwB,oBAAA,CAAqB;AAEnD,SAAS,gBAAA,GAAkC;AAChD,EAAA,OAAa,KAAA,CAAA,UAAA,CAAW,oBAAoB,CAAA,IAAK,kBAAA,EAAmB;AACtE;AAEO,SAAS,wBAAA,GAAiD;AAC/D,EAAA,OAAa,iBAAW,oBAAoB,CAAA;AAC9C;AAGO,SAAS,uBAAuB,YAAA,EAA6C;AAClF,EAAA,OAAO,kBAAiB,CAAE,gBAAA,CAAiB,GAAA,CAAI,YAAY,KAAK,EAAC;AACnE","file":"chunk-YH25Y4FW.js","sourcesContent":["import type { ComponentType } from 'react'\n\n// ---------------------------------------------------------------------------\n// Uniform registry — the indirection layer that lets a pure-data AppManifest\n// reference code by string id. Generalizes the entity registry pattern to\n// components, blocks, pages, metrics, scaffolds and plugins.\n//\n// Naming convention: SDK/plugin artifacts use a namespaced id\n// (`agenda.week-view`, `crud.detail-header`); app-local custom code uses the\n// reserved `custom:` prefix (`custom:tannat.HarvestBoard`). The platform never\n// generates `custom:` ids — they only come from an app's registry.tsx.\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\nexport interface RegistryMeta {\n /** Human label for the platform editor. */\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 propsSchema?: JsonSchema\n}\n\nexport interface RegistryEntry<T> {\n id: string\n value: T\n meta: RegistryMeta\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 this.entries.set(id, { id, value, meta })\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 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\n// ---------------------------------------------------------------------------\n// Metric definitions (consumed by dashboard / reports / KPI panels).\n// ---------------------------------------------------------------------------\n\nexport type MetricFormat = 'number' | 'currency' | 'percent' | 'duration' | 'rating'\n\nexport interface MetricContext {\n tenantId?: string\n /** ISO date range the metric should compute over, when applicable. */\n range?: { from: string; to: string }\n [key: string]: unknown\n}\n\nexport interface MetricValue {\n value: number\n previousValue?: number\n trend?: 'up' | 'down' | 'flat'\n}\n\nexport interface MetricDefinition {\n id: string\n label?: string\n category?: string\n format?: MetricFormat\n compute: (ctx: MetricContext) => Promise<MetricValue> | MetricValue\n}\n\n// ---------------------------------------------------------------------------\n// Concrete registries. Components/blocks/pages/scaffolds hold React component\n// types; metrics hold definitions; plugins hold opaque manifests (typed at the\n// plugin layer to avoid a circular import).\n// ---------------------------------------------------------------------------\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyComponent = ComponentType<any>\n\nexport const componentRegistry = new Registry<AnyComponent>('component')\nexport const blockRegistry = new Registry<AnyComponent>('block')\nexport const pageRegistry = new Registry<AnyComponent>('page')\nexport const scaffoldRegistry = new Registry<AnyComponent>('scaffold')\nexport const metricRegistry = new Registry<MetricDefinition>('metric')\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const pluginRegistry = new Registry<any>('plugin')\n\n// Thin functional facade (the public API surface) -----------------------------\n\nexport const registerComponent = (id: string, c: AnyComponent, meta?: RegistryMeta) =>\n componentRegistry.register(id, c, meta)\nexport const getComponent = (id: string) => componentRegistry.get(id)\n\nexport const registerBlock = (id: string, c: AnyComponent, meta?: RegistryMeta) =>\n blockRegistry.register(id, c, meta)\nexport const getBlock = (id: string) => blockRegistry.get(id)\nexport const listBlocks = () => blockRegistry.list()\n\nexport const registerPage = (id: string, c: AnyComponent, meta?: RegistryMeta) =>\n pageRegistry.register(id, c, meta)\nexport const getPage = (id: string) => pageRegistry.get(id)\n\nexport const registerScaffold = (id: string, c: AnyComponent, meta?: RegistryMeta) =>\n scaffoldRegistry.register(id, c, meta)\nexport const getScaffold = (id: string) => scaffoldRegistry.get(id)\n\nexport const registerMetric = (def: MetricDefinition, meta?: RegistryMeta) =>\n metricRegistry.register(def.id, def, meta)\nexport const getMetric = (id: string) => metricRegistry.get(id)\nexport const listMetrics = () => metricRegistry.list()\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const registerPlugin = (id: string, manifest: any, meta?: RegistryMeta) =>\n pluginRegistry.register(id, manifest, meta)\nexport const getPlugin = (id: string) => pluginRegistry.get(id)\nexport const listPlugins = () => pluginRegistry.list()\n\n// Plugin factories — a generated app registers each installed @fayz-ai/plugin-*\n// factory by id (src/plugins.generated.ts), so a scaffold can resolve a\n// manifest's PluginRef (id + JSON config) to a live PluginManifest:\n// getPluginFactory(ref.id)?.(ref.config)\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type PluginFactory = (config?: Record<string, unknown>) => any\nexport const pluginFactoryRegistry = new Registry<PluginFactory>('plugin-factory')\nexport const registerPluginFactory = (id: string, factory: PluginFactory, meta?: RegistryMeta) =>\n pluginFactoryRegistry.register(id, factory, meta)\nexport const getPluginFactory = (id: string) => pluginFactoryRegistry.get(id)\nexport const listPluginFactories = () => pluginFactoryRegistry.list()\n","import * as React from 'react'\nimport type {\n PluginManifest,\n PluginRuntime,\n PluginRuntimeContext,\n PluginRuntimeIssue,\n PluginRuntimeRoute,\n PluginSettingsTab,\n PluginWidgetDefinition,\n PluginWidgetZone,\n ResolvedPluginManifest,\n ResolvedPluginWidget,\n TenantPluginBinding,\n PluginRegistryDef,\n PluginAITool,\n PluginNavigationEntry,\n PluginCapability,\n PluginWidgetVisibility,\n ResolvedDashboardWidget,\n DashboardSurface,\n} from '../types/plugins'\nimport type { FeatureDeclaration } from '../types/permissions'\nimport type { LimitDeclaration } from '../types/entitlements'\nimport type { ConnectorDefinition } from '../integrations'\nimport { getComponent } from '../registry'\n\n/** The plugin contract version this runtime understands. A plugin declaring a\n * higher apiVersion is rejected rather than mis-rendered. */\nexport const PLUGIN_API_VERSION = 1\n\n/** Resolve a plugin route/widget/settings/onboarding target to a component,\n * whether it provided the component directly or a registered component id. */\nexport function resolvePluginComponent(\n def: { component?: React.ComponentType<unknown>; componentId?: string },\n): React.ComponentType<unknown> | undefined {\n if (def.component) return def.component\n if (def.componentId) return getComponent(def.componentId) as React.ComponentType<unknown> | undefined\n return undefined\n}\n\ninterface ResolvePluginRuntimeOptions {\n plugins?: PluginManifest[]\n tenantPlugins?: TenantPluginBinding[]\n hasTenantBindings?: boolean\n context: PluginRuntimeContext\n}\n\nconst EMPTY_CONTEXT: PluginRuntimeContext = {\n tenant: null,\n user: null,\n currentPath: '/',\n matchedPath: '/',\n layout: 'sidebar',\n}\n\nfunction slugify(input: string): string {\n return input.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')\n}\n\nfunction matchesRoutePattern(pattern: string, currentPath: string): boolean {\n if (pattern === currentPath) return true\n if (pattern.endsWith('/*')) {\n const base = pattern.slice(0, -2)\n return currentPath === base || currentPath.startsWith(`${base}/`)\n }\n if (pattern.endsWith('*')) return currentPath.startsWith(pattern.slice(0, -1))\n return false\n}\n\nfunction isWidgetVisible(widget: ResolvedPluginWidget, context: PluginRuntimeContext): boolean {\n if (widget.permission && context.hasPermission && !context.hasPermission(widget.permission)) return false\n const visibility: PluginWidgetVisibility | undefined = widget.visibility\n if (!visibility) return true\n\n if (visibility.layouts && !visibility.layouts.includes(context.layout)) return false\n if (visibility.roles && context.user?.role && !visibility.roles.includes(context.user.role)) return false\n if (visibility.roles && !context.user?.role) return false\n if (visibility.plans && context.tenant?.plan && !visibility.plans.includes(context.tenant.plan)) return false\n if (visibility.plans && !context.tenant?.plan) return false\n if (visibility.routes && !visibility.routes.some((p) => matchesRoutePattern(p, context.currentPath))) return false\n if (visibility.excludeRoutes?.some((p) => matchesRoutePattern(p, context.currentPath))) return false\n if (visibility.permissions?.length) {\n if (!context.hasPermission) return false\n if (!visibility.permissions.every((req) => context.hasPermission?.(req))) return false\n }\n if (visibility.when && !visibility.when(context)) return false\n return true\n}\n\nfunction normalizeSettingsTabs(plugin: PluginManifest): PluginSettingsTab[] {\n return (plugin.settings ?? []).map((entry, index) => ({\n ...entry,\n pluginId: entry.pluginId ?? plugin.id,\n order: entry.order ?? index,\n id: entry.id ?? `${plugin.id}-${slugify(entry.label)}`,\n }))\n}\n\nfunction createEmptyRuntime(context: PluginRuntimeContext = EMPTY_CONTEXT): PluginRuntime {\n return {\n context,\n plugins: [],\n activePlugins: [],\n routes: [],\n navigation: [],\n settingsTabs: [],\n widgets: [],\n dashboardWidgets: [],\n capabilities: [],\n aiTools: [],\n registries: new Map(),\n connectorsByHost: new Map(),\n pluginFeatures: [],\n pluginLimits: [],\n issues: [],\n }\n}\n\nexport function definePlugin<T extends PluginManifest>(plugin: T): T {\n return plugin\n}\n\nexport function resolvePluginRuntime({\n plugins = [],\n tenantPlugins = [],\n hasTenantBindings,\n context,\n}: ResolvePluginRuntimeOptions): PluginRuntime {\n if (plugins.length === 0) return createEmptyRuntime(context)\n\n const issues: PluginRuntimeIssue[] = []\n const normalizedPlugins = new Map<string, PluginManifest>()\n\n for (const plugin of plugins) {\n if (normalizedPlugins.has(plugin.id)) {\n issues.push({ type: 'duplicate_plugin', pluginId: plugin.id, message: `Plugin \"${plugin.id}\" registered more than once.` })\n continue\n }\n if (plugin.apiVersion != null && plugin.apiVersion > PLUGIN_API_VERSION) {\n issues.push({\n type: 'incompatible_api_version',\n pluginId: plugin.id,\n message: `Plugin \"${plugin.id}\" requires plugin API v${plugin.apiVersion}, but this runtime supports v${PLUGIN_API_VERSION}. Upgrade @fayz-ai/core.`,\n })\n continue\n }\n normalizedPlugins.set(plugin.id, plugin)\n }\n\n const bindings = new Map<string, TenantPluginBinding>()\n for (const b of tenantPlugins) bindings.set(b.pluginId, b)\n const bindingsAreManaged = hasTenantBindings ?? tenantPlugins.length > 0\n\n const requested = new Set<string>()\n const activationReason = new Map<string, ResolvedPluginManifest['activationReason']>()\n\n for (const plugin of normalizedPlugins.values()) {\n const binding = bindings.get(plugin.id)\n if (binding?.status === 'active') {\n requested.add(plugin.id)\n activationReason.set(plugin.id, 'tenant')\n continue\n }\n if (plugin.defaultEnabled === true || (!bindingsAreManaged && plugin.defaultEnabled !== false)) {\n requested.add(plugin.id)\n activationReason.set(plugin.id, 'default')\n }\n }\n\n const orderedIds: string[] = []\n const visiting = new Set<string>()\n const visited = new Set<string>()\n\n function visit(pluginId: string, ancestry: string[] = []): void {\n if (visited.has(pluginId)) return\n const plugin = normalizedPlugins.get(pluginId)\n if (!plugin) return\n if (visiting.has(pluginId)) {\n issues.push({ type: 'circular_dependency', pluginId, message: `Circular dependency: ${[...ancestry, pluginId].join(' -> ')}.` })\n return\n }\n visiting.add(pluginId)\n for (const depId of plugin.dependencies ?? []) {\n if (!normalizedPlugins.has(depId)) {\n issues.push({ type: 'missing_dependency', pluginId, dependencyId: depId, message: `Plugin \"${plugin.id}\" depends on missing plugin \"${depId}\".` })\n continue\n }\n if (requested.has(pluginId) && !requested.has(depId)) {\n requested.add(depId)\n activationReason.set(depId, 'dependency')\n }\n visit(depId, [...ancestry, pluginId])\n }\n visiting.delete(pluginId)\n visited.add(pluginId)\n orderedIds.push(pluginId)\n }\n\n for (const id of normalizedPlugins.keys()) visit(id)\n\n const resolvedById = new Map<string, ResolvedPluginManifest>()\n\n for (const pluginId of orderedIds) {\n const plugin = normalizedPlugins.get(pluginId)\n if (!plugin) continue\n const binding = bindings.get(plugin.id)\n const missing = (plugin.dependencies ?? []).filter((id) => !normalizedPlugins.has(id))\n const compatible = !plugin.verticalId || plugin.verticalId === context.tenant?.verticalId\n if (!compatible) {\n issues.push({ type: 'vertical_mismatch', pluginId: plugin.id, message: `Plugin \"${plugin.id}\" requires vertical \"${plugin.verticalId}\".` })\n }\n const reason = activationReason.get(plugin.id) ?? 'inactive'\n const depsReady = (plugin.dependencies ?? []).every((id) => resolvedById.get(id)?.isActive)\n const explicitlyDisabled = binding?.status === 'disabled' || binding?.status === 'removed'\n const shouldActivate = reason === 'dependency' ? true : requested.has(plugin.id) && !explicitlyDisabled\n const isActive = shouldActivate && compatible && missing.length === 0 && depsReady\n\n resolvedById.set(plugin.id, {\n ...plugin,\n status: isActive ? 'active' : (binding?.status ?? 'disabled'),\n isActive,\n activationReason: isActive ? reason : 'inactive',\n config: binding?.config ?? {},\n missingDependencies: missing,\n settingsTabs: normalizeSettingsTabs(plugin),\n widgets: plugin.widgets ?? [],\n resolvedRegistries: plugin.registries ?? [],\n resolvedAITools: plugin.aiTools ?? [],\n })\n }\n\n const resolvedPlugins = orderedIds\n .map((id) => resolvedById.get(id))\n .filter((p): p is ResolvedPluginManifest => Boolean(p))\n\n const activePlugins = resolvedPlugins.filter((p) => p.isActive)\n const routes: PluginRuntimeRoute[] = []\n const navigation: PluginNavigationEntry[] = []\n const settingsTabs: PluginSettingsTab[] = []\n const widgets: ResolvedPluginWidget[] = []\n const dashboardWidgets: ResolvedDashboardWidget[] = []\n const capabilities: PluginCapability[] = []\n const aiTools: PluginAITool[] = []\n const registries = new Map<string, PluginRegistryDef[]>()\n const connectorsByHost = new Map<string, ConnectorDefinition[]>()\n const pluginFeatures: FeatureDeclaration[] = []\n const pluginLimits: LimitDeclaration[] = []\n\n for (const plugin of activePlugins) {\n routes.push(...plugin.routes.map((r) => ({ ...r, plugin })))\n navigation.push(...plugin.navigation.map((entry, i) => ({\n ...entry,\n id: entry.id ?? `${plugin.id}:${entry.route}:${i}`,\n icon: entry.icon ?? plugin.icon,\n })))\n settingsTabs.push(...plugin.settingsTabs)\n capabilities.push(...(plugin.capabilities ?? []))\n aiTools.push(...plugin.resolvedAITools)\n if (plugin.resolvedRegistries.length > 0) registries.set(plugin.id, plugin.resolvedRegistries)\n // Group each addon's connectors under the host plugin they extend.\n for (const connector of plugin.connectors ?? []) {\n const list = connectorsByHost.get(connector.hostPluginId) ?? []\n list.push(connector)\n connectorsByHost.set(connector.hostPluginId, list)\n }\n if (plugin.declaredFeatures) pluginFeatures.push(...plugin.declaredFeatures)\n if (plugin.declaredLimits) pluginLimits.push(...plugin.declaredLimits)\n widgets.push(...plugin.widgets.map((w, i) => ({\n ...w,\n order: w.order ?? i,\n config: { ...plugin.config, ...(w.props ?? {}) },\n plugin,\n })))\n dashboardWidgets.push(...(plugin.dashboardWidgets ?? []).map((w, i) => ({\n ...w,\n domain: w.domain ?? plugin.id,\n order: w.defaultOrder ?? i,\n plugin,\n })))\n }\n\n navigation.sort((a, b) => {\n const order = { main: 0, secondary: 1, settings: 2 }\n return (order[a.section] ?? 99) - (order[b.section] ?? 99) || a.position - b.position\n })\n settingsTabs.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))\n widgets.sort((a, b) => a.zone !== b.zone ? a.zone.localeCompare(b.zone) : a.order - b.order)\n dashboardWidgets.sort((a, b) => a.order - b.order)\n\n return { context, plugins: resolvedPlugins, activePlugins, routes, navigation, settingsTabs, widgets, dashboardWidgets, capabilities, aiTools, issues, registries, connectorsByHost, pluginFeatures, pluginLimits }\n}\n\nexport function getWidgetsForZone(\n runtime: PluginRuntime,\n zone: PluginWidgetZone,\n contextOverrides?: Partial<PluginRuntimeContext>,\n): ResolvedPluginWidget[] {\n const ctx = { ...runtime.context, ...contextOverrides }\n return runtime.widgets.filter((w) => w.zone === zone && isWidgetVisible(w, ctx))\n}\n\nexport function getDashboardWidgets(\n runtime: PluginRuntime,\n options: { surface: DashboardSurface; domain?: string; contextOverrides?: Partial<PluginRuntimeContext> },\n): ResolvedDashboardWidget[] {\n const ctx = { ...runtime.context, ...options.contextOverrides }\n return runtime.dashboardWidgets.filter((w) => {\n const surfaces = w.surfaces ?? ['home', 'plugin-home']\n if (!surfaces.includes(options.surface)) return false\n if (options.domain && w.domain !== options.domain) return false\n if (w.verticalId && ctx.tenant?.verticalId && w.verticalId !== ctx.tenant.verticalId) return false\n if (w.permission && ctx.hasPermission && !ctx.hasPermission(w.permission)) return false\n return true\n })\n}\n\nconst PluginRuntimeContext = React.createContext<PluginRuntime | null>(null)\nexport const PluginRuntimeProvider = PluginRuntimeContext.Provider\n\nexport function usePluginRuntime(): PluginRuntime {\n return React.useContext(PluginRuntimeContext) ?? createEmptyRuntime()\n}\n\nexport function usePluginRuntimeOptional(): PluginRuntime | null {\n return React.useContext(PluginRuntimeContext)\n}\n\n/** Connectors contributed by addon plugins that extend the given host plugin. */\nexport function useConnectorsForPlugin(hostPluginId: string): ConnectorDefinition[] {\n return usePluginRuntime().connectorsByHost.get(hostPluginId) ?? []\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/integrations/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/phone/index.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAA;IACZ,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAA;IACZ,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAA;CACb;AAyBD,eAAO,MAAM,SAAS,EAAE,UAAU,EAAqD,CAAA;AAEvF,eAAO,MAAM,eAAe,OAAO,CAAA;AAInC,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAE/D;AAED,kCAAkC;AAClC,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAa7D;AAED,4CAA4C;AAC5C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAInD"}
|
package/dist/seo/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mFAAmF;IACnF,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CACxC;AAED,8CAA8C;AAC9C,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AA8BD,oFAAoF;AACpF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0BhD;AAED,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAO9C;AAID,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWjF;AAED,+CAA+C;AAC/C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tenant/index.ts"],"names":[],"mappings":"AAUA,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAM9D;AAED,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAGtE;AAED;6CAC6C;AAC7C,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAEtD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAUD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAsD3E;AAMD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAiBlE"}
|
package/src/access/denial.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { DenyReason } from './engine'
|
|
2
|
-
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
// The structured denial an AGENT surface returns instead of failing silently
|
|
5
|
-
// (docs/ENTITLEMENTS.md § "Superfície de agentes de IA"). One shape for every
|
|
6
|
-
// executor — FAB client-plane, the Fayz broker, and the pool RPCs (which emit
|
|
7
|
-
// its jsonb mirror in their `denial` field) — so the model can explain the
|
|
8
|
-
// denial and offer the upgrade path conversationally.
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
|
|
11
|
-
/** Where a denied tenant goes to upgrade — the conversational UpgradeModal. */
|
|
12
|
-
export const UPGRADE_URL = '/settings/subscription'
|
|
13
|
-
|
|
14
|
-
export interface AgentDenialLimit {
|
|
15
|
-
key: string
|
|
16
|
-
max: number
|
|
17
|
-
used: number
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface AgentDenial {
|
|
21
|
-
allowed: false
|
|
22
|
-
reason: DenyReason
|
|
23
|
-
/** Present when `reason === 'limit'`. */
|
|
24
|
-
limit?: AgentDenialLimit
|
|
25
|
-
upgradeUrl: string
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type AgentGuardResult = { allowed: true } | AgentDenial
|
|
29
|
-
|
|
30
|
-
/** Build a denial with the canonical upgrade URL attached. */
|
|
31
|
-
export function agentDenial(reason: DenyReason, limit?: AgentDenialLimit): AgentDenial {
|
|
32
|
-
return { allowed: false, reason, ...(limit ? { limit } : {}), upgradeUrl: UPGRADE_URL }
|
|
33
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import type { PermissionProfile } from '../types/permissions'
|
|
3
|
-
import { profileHasPermission, isOwnerProfile, resolveAccess } from './engine'
|
|
4
|
-
import { agentDenial, UPGRADE_URL } from './denial'
|
|
5
|
-
|
|
6
|
-
// The composition matrix (role × plan × limit math) is covered by
|
|
7
|
-
// packages/saas/src/access/resolver.test.ts, which now runs against this
|
|
8
|
-
// engine through the saas re-export — parity by construction. Here we cover
|
|
9
|
-
// the pieces that are new or only reachable from core.
|
|
10
|
-
|
|
11
|
-
const staff: PermissionProfile = { id: 'staff', name: 'Staff', grants: { clients: ['read'] } }
|
|
12
|
-
|
|
13
|
-
describe('profileHasPermission', () => {
|
|
14
|
-
it('null profile is allow-all (catalog not hydrated yet)', () => {
|
|
15
|
-
expect(profileHasPermission(null, 'anything', 'delete')).toBe(true)
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
it('owner matches by id or (localized) name', () => {
|
|
19
|
-
expect(isOwnerProfile({ id: 'owner', name: 'Proprietário', grants: {} })).toBe(true)
|
|
20
|
-
expect(isOwnerProfile({ id: 'x', name: 'Owner', grants: {} })).toBe(true)
|
|
21
|
-
expect(isOwnerProfile(staff)).toBe(false)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('manage satisfies any action; empty grant list denies actionless check', () => {
|
|
25
|
-
const manager: PermissionProfile = { id: 'm', name: 'M', grants: { clients: ['manage'], reports: [] } }
|
|
26
|
-
expect(profileHasPermission(manager, 'clients', 'delete')).toBe(true)
|
|
27
|
-
expect(profileHasPermission(manager, 'reports')).toBe(false)
|
|
28
|
-
})
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
describe('agentDenial', () => {
|
|
32
|
-
it('carries the canonical upgrade URL', () => {
|
|
33
|
-
expect(agentDenial('plan')).toEqual({ allowed: false, reason: 'plan', upgradeUrl: UPGRADE_URL })
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('carries limit details for limit denials', () => {
|
|
37
|
-
const d = agentDenial('limit', { key: 'clients', max: 100, used: 100 })
|
|
38
|
-
expect(d.limit).toEqual({ key: 'clients', max: 100, used: 100 })
|
|
39
|
-
expect(d.reason).toBe('limit')
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('shape matches what resolveAccess produces for the same reason', () => {
|
|
43
|
-
const decision = resolveAccess({ profile: staff, plan: null }, 'marketing')
|
|
44
|
-
expect(decision.allowed).toBe(false)
|
|
45
|
-
const d = agentDenial(decision.reason!)
|
|
46
|
-
expect(d.reason).toBe('role')
|
|
47
|
-
})
|
|
48
|
-
})
|
package/src/access/engine.ts
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import type { PermissionProfile, PermissionAction, SystemPermission } from '../types/permissions'
|
|
2
|
-
import type { Plan } from '../types/billing'
|
|
3
|
-
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
// The access engine — the ONE implementation of the role × plan × limit
|
|
6
|
-
// decision, shared by every runtime that gates anything:
|
|
7
|
-
//
|
|
8
|
-
// - browser (saas AccessProvider / PermissionsProvider re-export from here)
|
|
9
|
-
// - headless client-plane (saas access/headless.ts)
|
|
10
|
-
// - the Fayz broker (server-side agent authorization imports this package)
|
|
11
|
-
//
|
|
12
|
-
// Hard constraint: this module (and everything under core/src/access) must stay
|
|
13
|
-
// free of React, zustand and supabase — pure functions over plain data — so the
|
|
14
|
-
// exact same code runs in Node/edge. Guarded by scripts/check-access-purity.mjs.
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
|
|
17
|
-
/** Why an access request was denied. `limit` only occurs on guarded writes. */
|
|
18
|
-
export type DenyReason = 'role' | 'plan' | 'limit'
|
|
19
|
-
|
|
20
|
-
export interface AccessDecision {
|
|
21
|
-
allowed: boolean
|
|
22
|
-
reason?: DenyReason
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** The minimal subject a decision needs — a projection of any richer session. */
|
|
26
|
-
export interface AccessSubject {
|
|
27
|
-
/** Effective RBAC profile — the previewed role during impersonation. */
|
|
28
|
-
profile: PermissionProfile | null
|
|
29
|
-
/** The tenant's currently-active plan. */
|
|
30
|
-
plan: Plan | null
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* The org owner has every permission implicitly. Owner is represented by the
|
|
35
|
-
* canonical role id `owner` across adapters (see org/adapters/supabase.ts
|
|
36
|
-
* buildPermissionProfiles, which also grants owner all catalog perms, and the
|
|
37
|
-
* mock adapter's `owner` fallback). We match by id first, falling back to the
|
|
38
|
-
* (possibly localized) name for safety.
|
|
39
|
-
*/
|
|
40
|
-
export function isOwnerProfile(profile: PermissionProfile): boolean {
|
|
41
|
-
return profile.id === 'owner' || profile.name?.toLowerCase() === 'owner'
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* The single role-side permission check. The plan axis composes ON TOP of it in
|
|
46
|
-
* {@link resolveAccess} instead of reimplementing owner-bypass / `manage`
|
|
47
|
-
* semantics.
|
|
48
|
-
*/
|
|
49
|
-
export function profileHasPermission(
|
|
50
|
-
profile: PermissionProfile | null,
|
|
51
|
-
feature: string,
|
|
52
|
-
action?: string,
|
|
53
|
-
): boolean {
|
|
54
|
-
if (!profile) return true
|
|
55
|
-
|
|
56
|
-
// Owner bypass: never lock the owner out, even if the RBAC catalog is empty
|
|
57
|
-
// or still loading. Because permission checks read the *effective* profile,
|
|
58
|
-
// an owner previewing a non-owner role correctly loses this bypass — the
|
|
59
|
-
// preview stays honest.
|
|
60
|
-
if (isOwnerProfile(profile)) return true
|
|
61
|
-
|
|
62
|
-
const actions = profile.grants[feature]
|
|
63
|
-
if (!actions) return false
|
|
64
|
-
|
|
65
|
-
if (!action) return actions.length > 0
|
|
66
|
-
|
|
67
|
-
return actions.includes(action) || actions.includes('manage')
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* The org-management side of a profile: managing team, billing, settings and
|
|
72
|
-
* permissions themselves. Separate axis from `grants` — these gate the settings
|
|
73
|
-
* tabs, not a feature's rows — and it follows the same owner bypass, so the one
|
|
74
|
-
* person who can hand out access is never locked out of doing it.
|
|
75
|
-
*/
|
|
76
|
-
export function profileHasSystemPermission(
|
|
77
|
-
profile: PermissionProfile | null,
|
|
78
|
-
permission: SystemPermission,
|
|
79
|
-
): boolean {
|
|
80
|
-
if (!profile) return true
|
|
81
|
-
if (isOwnerProfile(profile)) return true
|
|
82
|
-
return profile.systemPermissions?.includes(permission) ?? false
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Does the current plan entitle `feature`? A plan gates a feature ONLY with an
|
|
87
|
-
* explicit `false`; absent means "not gated by this plan" (allowed). This keeps
|
|
88
|
-
* entitlements additive and safe: a feature the plan has never heard of stays
|
|
89
|
-
* open rather than silently locking.
|
|
90
|
-
*/
|
|
91
|
-
export function isEntitledByPlan(plan: Plan | null, feature: string): boolean {
|
|
92
|
-
return plan?.entitlements?.features?.[feature] !== false
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* The single access decision: role FIRST, then plan.
|
|
97
|
-
*
|
|
98
|
-
* 1. Role — reuses `profileHasPermission` (owner bypass + `manage` semantics
|
|
99
|
-
* live there, and impersonation composes for free because `profile` is the
|
|
100
|
-
* previewed role). Denied → `{ allowed:false, reason:'role' }`.
|
|
101
|
-
* 2. Plan — even the owner does NOT bypass the plan: upgrading is the tenant's
|
|
102
|
-
* decision, not a role power. Denied → `{ allowed:false, reason:'plan' }`.
|
|
103
|
-
*/
|
|
104
|
-
export function resolveAccess(
|
|
105
|
-
subject: AccessSubject,
|
|
106
|
-
feature: string,
|
|
107
|
-
action?: PermissionAction,
|
|
108
|
-
): AccessDecision {
|
|
109
|
-
if (!profileHasPermission(subject.profile, feature, action)) {
|
|
110
|
-
return { allowed: false, reason: 'role' }
|
|
111
|
-
}
|
|
112
|
-
if (!isEntitledByPlan(subject.plan, feature)) {
|
|
113
|
-
return { allowed: false, reason: 'plan' }
|
|
114
|
-
}
|
|
115
|
-
return { allowed: true }
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Pure numeric side of a limit: given the plan cap, whether a countable
|
|
120
|
-
* declaration exists, and the current usage, derive the limit math. Unlimited
|
|
121
|
-
* when there's no declaration to count, no cap on the plan, or the cap is `-1`.
|
|
122
|
-
*/
|
|
123
|
-
export function resolveLimit(params: { cap: number | undefined; hasDeclaration: boolean; used: number }): {
|
|
124
|
-
max: number
|
|
125
|
-
used: number
|
|
126
|
-
remaining: number
|
|
127
|
-
atLimit: boolean
|
|
128
|
-
unlimited: boolean
|
|
129
|
-
} {
|
|
130
|
-
const { cap, hasDeclaration, used } = params
|
|
131
|
-
const unlimited = !hasDeclaration || cap === undefined || cap === -1
|
|
132
|
-
const max = unlimited ? Infinity : cap
|
|
133
|
-
const remaining = unlimited ? Infinity : Math.max(0, max - used)
|
|
134
|
-
const atLimit = !unlimited && used >= max
|
|
135
|
-
return { max, used, remaining, atLimit, unlimited }
|
|
136
|
-
}
|
package/src/access/index.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
isOwnerProfile,
|
|
3
|
-
profileHasPermission,
|
|
4
|
-
profileHasSystemPermission,
|
|
5
|
-
isEntitledByPlan,
|
|
6
|
-
resolveAccess,
|
|
7
|
-
resolveLimit,
|
|
8
|
-
} from './engine'
|
|
9
|
-
export type { DenyReason, AccessDecision, AccessSubject } from './engine'
|
|
10
|
-
|
|
11
|
-
export { UPGRADE_URL, agentDenial } from './denial'
|
|
12
|
-
export type { AgentDenial, AgentDenialLimit, AgentGuardResult } from './denial'
|
|
13
|
-
|
|
14
|
-
export { mergeLimitDeclarations } from './limits'
|
package/src/access/limits.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { LimitDeclaration } from '../types/entitlements'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The 4-layer limit-declaration merge, extracted so the browser AccessProvider
|
|
5
|
-
* and the manifest derivation (`fayz manifest emit`) resolve the EXACT same
|
|
6
|
-
* final set: core built-ins < entity-derived < plugin `declaredLimits` < app
|
|
7
|
-
* overrides. Later layers win by key. Pure: pass the layers in, get the merge
|
|
8
|
-
* out — deriving a declaration FROM an entity stays at the call site.
|
|
9
|
-
*/
|
|
10
|
-
export function mergeLimitDeclarations(
|
|
11
|
-
...layers: Array<LimitDeclaration[] | undefined>
|
|
12
|
-
): LimitDeclaration[] {
|
|
13
|
-
const byKey = new Map<string, LimitDeclaration>()
|
|
14
|
-
for (const layer of layers) {
|
|
15
|
-
for (const decl of layer ?? []) byKey.set(decl.key, decl)
|
|
16
|
-
}
|
|
17
|
-
return Array.from(byKey.values())
|
|
18
|
-
}
|
package/src/address/index.ts
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Postal code → address lookup (SDK-level — shared by any surface that collects
|
|
3
|
-
// an address: storefront checkout, the SaaS address book, CRM, booking).
|
|
4
|
-
//
|
|
5
|
-
// Sits beside ./phone for the same reason: knowing that a Brazilian CEP is
|
|
6
|
-
// eight digits, and that '01310100' means Avenida Paulista, is not a
|
|
7
|
-
// storefront concern. It belongs wherever an address is typed.
|
|
8
|
-
//
|
|
9
|
-
// The lookup itself is behind an interface. ViaCEP is the default because it is
|
|
10
|
-
// free, keyless and CORS-enabled, but it is a third party the merchant does not
|
|
11
|
-
// control — so swapping it for an edge-function proxy (shared cache, no
|
|
12
|
-
// third-party call from the shopper's browser) must be one line, not a rewrite.
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* An address as a postal service knows it: everything except the parts only the
|
|
17
|
-
* resident can supply (number, complement).
|
|
18
|
-
*
|
|
19
|
-
* Field names mirror ShippingAddressInput in @fayz-ai/shop so the value crosses
|
|
20
|
-
* from lookup to checkout to the order with no translation step in between.
|
|
21
|
-
*/
|
|
22
|
-
export interface PostalAddress {
|
|
23
|
-
postalCode: string
|
|
24
|
-
street: string
|
|
25
|
-
district: string
|
|
26
|
-
city: string
|
|
27
|
-
state: string
|
|
28
|
-
country: string
|
|
29
|
-
/** IBGE municipality code when the source provides one — useful for tax later. */
|
|
30
|
-
cityCode?: string
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Where a postal code is resolved. Implementations must not throw for a
|
|
34
|
-
* well-formed code that simply does not exist — that is `null`, not an error. */
|
|
35
|
-
export interface PostalLookupProvider {
|
|
36
|
-
lookup(postalCode: string): Promise<PostalAddress | null>
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Keep only digits. */
|
|
40
|
-
export function normalizePostalCode(value: string): string {
|
|
41
|
-
return (value || '').replace(/\D/g, '')
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** '01310100' | '01310-100' -> '01310-100'. Partial input formats progressively. */
|
|
45
|
-
export function formatPostalCode(value: string): string {
|
|
46
|
-
const digits = normalizePostalCode(value).slice(0, 8)
|
|
47
|
-
return digits.length > 5 ? `${digits.slice(0, 5)}-${digits.slice(5)}` : digits
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** A Brazilian CEP is exactly eight digits. */
|
|
51
|
-
export function isValidPostalCode(value: string): boolean {
|
|
52
|
-
return normalizePostalCode(value).length === 8
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
// Cache
|
|
57
|
-
//
|
|
58
|
-
// A CEP maps to the same street for years, so the second lookup of one should
|
|
59
|
-
// never leave the browser. This also keeps a busy storefront well clear of
|
|
60
|
-
// ViaCEP's per-IP rate limit. localStorage when there is a window, an in-memory
|
|
61
|
-
// Map otherwise (SSR, tests, node) — never a hard failure over a cache miss.
|
|
62
|
-
// ---------------------------------------------------------------------------
|
|
63
|
-
|
|
64
|
-
const CACHE_KEY = 'fayz.postal.cache.v1'
|
|
65
|
-
const memoryCache = new Map<string, PostalAddress>()
|
|
66
|
-
|
|
67
|
-
function readCache(code: string): PostalAddress | undefined {
|
|
68
|
-
const hit = memoryCache.get(code)
|
|
69
|
-
if (hit) return hit
|
|
70
|
-
try {
|
|
71
|
-
const raw = globalThis.localStorage?.getItem(CACHE_KEY)
|
|
72
|
-
if (!raw) return undefined
|
|
73
|
-
const all = JSON.parse(raw) as Record<string, PostalAddress>
|
|
74
|
-
const stored = all[code]
|
|
75
|
-
if (stored) memoryCache.set(code, stored)
|
|
76
|
-
return stored
|
|
77
|
-
} catch {
|
|
78
|
-
return undefined
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function writeCache(code: string, address: PostalAddress): void {
|
|
83
|
-
memoryCache.set(code, address)
|
|
84
|
-
try {
|
|
85
|
-
const store = globalThis.localStorage
|
|
86
|
-
if (!store) return
|
|
87
|
-
const raw = store.getItem(CACHE_KEY)
|
|
88
|
-
const all = raw ? (JSON.parse(raw) as Record<string, PostalAddress>) : {}
|
|
89
|
-
all[code] = address
|
|
90
|
-
store.setItem(CACHE_KEY, JSON.stringify(all))
|
|
91
|
-
} catch {
|
|
92
|
-
/* quota or private mode — the in-memory copy still stands for this session */
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/** Drop the cache. Exposed for tests and for a "wrong address?" escape hatch. */
|
|
97
|
-
export function clearPostalCache(): void {
|
|
98
|
-
memoryCache.clear()
|
|
99
|
-
try {
|
|
100
|
-
globalThis.localStorage?.removeItem(CACHE_KEY)
|
|
101
|
-
} catch {
|
|
102
|
-
/* ignore */
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// ---------------------------------------------------------------------------
|
|
107
|
-
// ViaCEP
|
|
108
|
-
// ---------------------------------------------------------------------------
|
|
109
|
-
|
|
110
|
-
interface ViaCepResponse {
|
|
111
|
-
cep?: string
|
|
112
|
-
logradouro?: string
|
|
113
|
-
bairro?: string
|
|
114
|
-
localidade?: string
|
|
115
|
-
uf?: string
|
|
116
|
-
ibge?: string
|
|
117
|
-
erro?: boolean | string
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* ViaCEP (https://viacep.com.br). Free, no key, CORS-enabled.
|
|
122
|
-
*
|
|
123
|
-
* The trap: an unknown CEP does NOT come back as 404. ViaCEP answers HTTP 200
|
|
124
|
-
* with `{"erro": true}` (and, on some deploys, the string "true"), so checking
|
|
125
|
-
* response.ok alone yields an address of empty strings that silently overwrites
|
|
126
|
-
* whatever the shopper had typed. Both shapes are treated as "not found".
|
|
127
|
-
*/
|
|
128
|
-
export function createViaCepProvider(options?: { fetcher?: typeof fetch }): PostalLookupProvider {
|
|
129
|
-
const fetcher = options?.fetcher ?? globalThis.fetch
|
|
130
|
-
return {
|
|
131
|
-
async lookup(postalCode: string): Promise<PostalAddress | null> {
|
|
132
|
-
const code = normalizePostalCode(postalCode)
|
|
133
|
-
if (code.length !== 8) return null
|
|
134
|
-
|
|
135
|
-
const response = await fetcher(`https://viacep.com.br/ws/${code}/json/`)
|
|
136
|
-
if (!response.ok) throw new Error(`Consulta de CEP falhou (${response.status})`)
|
|
137
|
-
|
|
138
|
-
const data = (await response.json()) as ViaCepResponse
|
|
139
|
-
if (data.erro === true || data.erro === 'true' || !data.localidade) return null
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
postalCode: code,
|
|
143
|
-
street: data.logradouro ?? '',
|
|
144
|
-
district: data.bairro ?? '',
|
|
145
|
-
city: data.localidade,
|
|
146
|
-
state: (data.uf ?? '').toUpperCase(),
|
|
147
|
-
country: 'BR',
|
|
148
|
-
cityCode: data.ibge || undefined,
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// ---------------------------------------------------------------------------
|
|
155
|
-
// Module-level resolver — same shape as setShopTenantResolver /
|
|
156
|
-
// setShopAccessTokenResolver, so an app overrides the source once at boot
|
|
157
|
-
// instead of threading a provider through every component that needs a CEP.
|
|
158
|
-
// ---------------------------------------------------------------------------
|
|
159
|
-
|
|
160
|
-
let _provider: PostalLookupProvider | null = null
|
|
161
|
-
|
|
162
|
-
export function setPostalLookupProvider(provider: PostalLookupProvider | null): void {
|
|
163
|
-
_provider = provider
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export function getPostalLookupProvider(): PostalLookupProvider {
|
|
167
|
-
if (!_provider) _provider = createViaCepProvider()
|
|
168
|
-
return _provider
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Resolve a postal code to an address, through the cache.
|
|
173
|
-
*
|
|
174
|
-
* Returns null for a code that is malformed or does not exist; throws only when
|
|
175
|
-
* the lookup itself failed (offline, provider down), so a caller can tell
|
|
176
|
-
* "no such CEP" from "we could not check right now" and say the right thing.
|
|
177
|
-
*/
|
|
178
|
-
export async function lookupPostalCode(postalCode: string): Promise<PostalAddress | null> {
|
|
179
|
-
const code = normalizePostalCode(postalCode)
|
|
180
|
-
if (code.length !== 8) return null
|
|
181
|
-
|
|
182
|
-
const cached = readCache(code)
|
|
183
|
-
if (cached) return cached
|
|
184
|
-
|
|
185
|
-
const address = await getPostalLookupProvider().lookup(code)
|
|
186
|
-
if (address) writeCache(code, address)
|
|
187
|
-
return address
|
|
188
|
-
}
|
package/src/app/render.tsx
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
import { getScaffold } from '../registry'
|
|
3
|
-
import { migrateManifest, validateManifest, CURRENT_MANIFEST_VERSION } from '../manifest'
|
|
4
|
-
import type { AppManifest } from '../manifest'
|
|
5
|
-
|
|
6
|
-
// ---------------------------------------------------------------------------
|
|
7
|
-
// defineApp / renderApp — the entry points that turn an AppManifest into a
|
|
8
|
-
// running app. Scaffolds (admin, storefront, portal) self-register into the
|
|
9
|
-
// scaffold registry when their package is imported, so core never depends on
|
|
10
|
-
// them: a generated app imports the scaffold package(s) it needs, then calls
|
|
11
|
-
// renderApp(manifest). createSaasApp / createStorefrontApp become sugar that
|
|
12
|
-
// builds a manifest and hands it here.
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
const ManifestContext = React.createContext<AppManifest | null>(null)
|
|
16
|
-
|
|
17
|
-
/** Access the active app manifest from any component under renderApp. */
|
|
18
|
-
export function useManifest(): AppManifest | null {
|
|
19
|
-
return React.useContext(ManifestContext)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Stamp + validate a manifest authored in code (the sugar path). */
|
|
23
|
-
export function defineApp(
|
|
24
|
-
manifest: Omit<AppManifest, 'manifestVersion'> & { manifestVersion?: number },
|
|
25
|
-
): AppManifest {
|
|
26
|
-
const full = {
|
|
27
|
-
...manifest,
|
|
28
|
-
manifestVersion: manifest.manifestVersion ?? CURRENT_MANIFEST_VERSION,
|
|
29
|
-
} as AppManifest
|
|
30
|
-
const problems = validateManifest(full)
|
|
31
|
-
if (problems.length) {
|
|
32
|
-
throw new Error(`Invalid AppManifest:\n - ${problems.join('\n - ')}`)
|
|
33
|
-
}
|
|
34
|
-
return full
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface RenderAppOptions {
|
|
38
|
-
/** Which surface to mount; defaults to the first declared surface. */
|
|
39
|
-
surface?: string
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Resolve, migrate and validate a manifest, then mount the scaffold for the
|
|
43
|
-
* chosen surface. Accepts a raw object (e.g. parsed app.manifest.json). */
|
|
44
|
-
export function renderApp(
|
|
45
|
-
input: AppManifest | Record<string, unknown>,
|
|
46
|
-
opts: RenderAppOptions = {},
|
|
47
|
-
): React.ReactElement {
|
|
48
|
-
const manifest = migrateManifest(input as Record<string, unknown>)
|
|
49
|
-
const problems = validateManifest(manifest)
|
|
50
|
-
if (problems.length) {
|
|
51
|
-
throw new Error(`Invalid AppManifest:\n - ${problems.join('\n - ')}`)
|
|
52
|
-
}
|
|
53
|
-
const surfaceName = opts.surface ?? Object.keys(manifest.surfaces)[0]
|
|
54
|
-
const surface = surfaceName ? manifest.surfaces[surfaceName] : undefined
|
|
55
|
-
if (!surface) {
|
|
56
|
-
throw new Error(`Surface "${surfaceName}" not found in manifest.`)
|
|
57
|
-
}
|
|
58
|
-
const Scaffold = getScaffold(surface.scaffold)
|
|
59
|
-
if (!Scaffold) {
|
|
60
|
-
throw new Error(
|
|
61
|
-
`Scaffold "${surface.scaffold}" is not registered. Call renderApp from the package that provides it (e.g. @fayz-ai/saas, @fayz-ai/portal, @fayz-ai/storefront) or call its register*Scaffold() first.`,
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
return React.createElement(
|
|
65
|
-
ManifestContext.Provider,
|
|
66
|
-
{ value: manifest },
|
|
67
|
-
React.createElement(Scaffold, { manifest, surface: surfaceName }),
|
|
68
|
-
)
|
|
69
|
-
}
|