@pilotiq/pilotiq 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/CHANGELOG.md +107 -0
  3. package/dist/Pilotiq.d.ts +72 -0
  4. package/dist/Pilotiq.d.ts.map +1 -1
  5. package/dist/Pilotiq.js +145 -0
  6. package/dist/Pilotiq.js.map +1 -1
  7. package/dist/PilotiqServiceProvider.d.ts +2 -0
  8. package/dist/PilotiqServiceProvider.d.ts.map +1 -1
  9. package/dist/PilotiqServiceProvider.js +60 -12
  10. package/dist/PilotiqServiceProvider.js.map +1 -1
  11. package/dist/actions/importFactory.d.ts +5 -0
  12. package/dist/actions/importFactory.d.ts.map +1 -1
  13. package/dist/actions/importFactory.js +20 -10
  14. package/dist/actions/importFactory.js.map +1 -1
  15. package/dist/orm/modelDefaults.d.ts +10 -1
  16. package/dist/orm/modelDefaults.d.ts.map +1 -1
  17. package/dist/orm/modelDefaults.js +7 -2
  18. package/dist/orm/modelDefaults.js.map +1 -1
  19. package/dist/pageData/forms.js +3 -3
  20. package/dist/pageData/forms.js.map +1 -1
  21. package/dist/pageData/misc.js +5 -5
  22. package/dist/pageData/misc.js.map +1 -1
  23. package/dist/pageData/navigation.d.ts.map +1 -1
  24. package/dist/pageData/navigation.js +11 -9
  25. package/dist/pageData/navigation.js.map +1 -1
  26. package/dist/pageData/relationPages.d.ts.map +1 -1
  27. package/dist/pageData/relationPages.js +7 -4
  28. package/dist/pageData/relationPages.js.map +1 -1
  29. package/dist/pageData/resourcePages.js +6 -6
  30. package/dist/pageData/resourcePages.js.map +1 -1
  31. package/dist/plugins/index.d.ts +3 -0
  32. package/dist/plugins/index.d.ts.map +1 -1
  33. package/dist/plugins/index.js +1 -0
  34. package/dist/plugins/index.js.map +1 -1
  35. package/dist/plugins/themeEditor.d.ts +20 -1
  36. package/dist/plugins/themeEditor.d.ts.map +1 -1
  37. package/dist/plugins/themeEditor.js +3 -1
  38. package/dist/plugins/themeEditor.js.map +1 -1
  39. package/dist/react/CollabRoomContext.d.ts +12 -0
  40. package/dist/react/CollabRoomContext.d.ts.map +1 -1
  41. package/dist/react/CollabRoomContext.js.map +1 -1
  42. package/dist/react/FormStateContext.d.ts +10 -0
  43. package/dist/react/FormStateContext.d.ts.map +1 -1
  44. package/dist/react/FormStateContext.js +12 -0
  45. package/dist/react/FormStateContext.js.map +1 -1
  46. package/dist/react/PendingSuggestionApplierRegistry.d.ts +12 -0
  47. package/dist/react/PendingSuggestionApplierRegistry.d.ts.map +1 -1
  48. package/dist/react/PendingSuggestionApplierRegistry.js +21 -1
  49. package/dist/react/PendingSuggestionApplierRegistry.js.map +1 -1
  50. package/dist/react/index.d.ts +2 -1
  51. package/dist/react/index.d.ts.map +1 -1
  52. package/dist/react/index.js +2 -1
  53. package/dist/react/index.js.map +1 -1
  54. package/dist/react/useCollabSeed.d.ts +23 -0
  55. package/dist/react/useCollabSeed.d.ts.map +1 -0
  56. package/dist/react/useCollabSeed.js +67 -0
  57. package/dist/react/useCollabSeed.js.map +1 -0
  58. package/dist/routes/globals.d.ts.map +1 -1
  59. package/dist/routes/globals.js +8 -22
  60. package/dist/routes/globals.js.map +1 -1
  61. package/dist/routes/helpers.d.ts +13 -0
  62. package/dist/routes/helpers.d.ts.map +1 -1
  63. package/dist/routes/helpers.js +25 -8
  64. package/dist/routes/helpers.js.map +1 -1
  65. package/dist/routes/resources.d.ts.map +1 -1
  66. package/dist/routes/resources.js +12 -34
  67. package/dist/routes/resources.js.map +1 -1
  68. package/dist/routes/theme.d.ts +4 -2
  69. package/dist/routes/theme.d.ts.map +1 -1
  70. package/dist/routes/theme.js +27 -26
  71. package/dist/routes/theme.js.map +1 -1
  72. package/dist/routes.d.ts.map +1 -1
  73. package/dist/routes.js +65 -37
  74. package/dist/routes.js.map +1 -1
  75. package/dist/theme/index.d.ts +2 -0
  76. package/dist/theme/index.d.ts.map +1 -1
  77. package/dist/theme/index.js +1 -0
  78. package/dist/theme/index.js.map +1 -1
  79. package/dist/theme/storage.d.ts +86 -0
  80. package/dist/theme/storage.d.ts.map +1 -0
  81. package/dist/theme/storage.js +52 -0
  82. package/dist/theme/storage.js.map +1 -0
  83. package/package.json +1 -1
  84. package/src/Pilotiq.perf.test.ts +252 -0
  85. package/src/Pilotiq.test.ts +4 -0
  86. package/src/Pilotiq.ts +166 -0
  87. package/src/PilotiqServiceProvider.ts +63 -11
  88. package/src/actions/importFactory.ts +31 -10
  89. package/src/orm/modelDefaults.ts +15 -2
  90. package/src/pageData/forms.ts +3 -3
  91. package/src/pageData/misc.ts +5 -5
  92. package/src/pageData/navigation.ts +11 -9
  93. package/src/pageData/relationPages.ts +5 -3
  94. package/src/pageData/resourcePages.ts +6 -6
  95. package/src/plugins/index.ts +7 -0
  96. package/src/plugins/themeEditor.test.ts +36 -0
  97. package/src/plugins/themeEditor.ts +22 -1
  98. package/src/react/CollabRoomContext.ts +12 -0
  99. package/src/react/FormStateContext.tsx +13 -0
  100. package/src/react/PendingSuggestionApplierRegistry.test.ts +97 -0
  101. package/src/react/PendingSuggestionApplierRegistry.ts +19 -1
  102. package/src/react/index.ts +2 -0
  103. package/src/react/useCollabSeed.ts +73 -0
  104. package/src/routes/globals.ts +8 -16
  105. package/src/routes/guard.test.ts +325 -0
  106. package/src/routes/helpers.ts +30 -8
  107. package/src/routes/resources.ts +12 -22
  108. package/src/routes/theme.ts +26 -44
  109. package/src/routes.ts +65 -36
  110. package/src/theme/index.ts +6 -0
  111. package/src/theme/storage.test.ts +126 -0
  112. package/src/theme/storage.ts +106 -0
package/dist/routes.js CHANGED
@@ -2,6 +2,7 @@ import { dispatchFormSubmit, findForms, selectForm } from './elements/dispatchFo
2
2
  import { RESERVED_RELATIONSHIP_TOKENS } from './RelationManager.js';
3
3
  import { Table } from './elements/Table.js';
4
4
  import { Column } from './Column.js';
5
+ import { wantsJson } from './routes/helpers.js';
5
6
  // `routes.ts` is split into a directory of focused modules under
6
7
  // `./routes/`. This file is the orchestrator — boot-time validation
7
8
  // loops + the per-Resource / per-Global / per-Page registration
@@ -170,43 +171,65 @@ export function registerPilotiqRoutes(router, pilotiq) {
170
171
  editableEnabled.add(R.getSlug());
171
172
  }
172
173
  }
173
- // ── Panel-level sibling routes ────────────────────────
174
- // Dashboard, _uploads, _widget, _search, _notifications.
175
- // Pulled out 2026-05-12 (Phase 2 of the routes.ts split).
176
- registerPanelRoutes(router, pilotiq, base);
177
- // ── Resource routes ───────────────────────────────────
178
- // List / view / create / edit / delete + soft-delete / actions /
179
- // widgets / deferred-table / reorder / per-row editable cells / the
180
- // four form-state companion endpoints / record sub-pages. Each
181
- // Resource also fans out into its registered relation managers
182
- // (depth-1 + depth-2). Pulled out 2026-05-12 (Phase 5 of the
183
- // routes.ts split).
184
- for (const R of cfg.resources) {
185
- registerResourceRoutes(router, pilotiq, R, base, {
186
- reorderable: reorderEnabled.has(R.getSlug()),
187
- editable: editableEnabled.has(R.getSlug()),
188
- });
189
- }
190
- // ── Globals (singletons — 2-segment, no /:id) ────────
191
- // Pulled out 2026-05-12 (Phase 3 of the routes.ts split).
192
- for (const G of cfg.globals) {
193
- registerGlobalRoutes(router, pilotiq, G, base);
194
- }
195
- // ── Custom pages (2-segment, slug route) ──────────────
196
- // Pulled out 2026-05-12 (Phase 3 of the routes.ts split).
197
- for (const PageClass of cfg.pages) {
198
- // The dashboard page lives at `${base}` (panel routes handle it);
199
- // skip it here so we don't register a duplicate `${pageUrl}` route
200
- // or a broken `${base}/` (when `slug = ''`).
201
- if (cfg.dashboardPage === PageClass)
202
- continue;
203
- registerCustomPageRoutes(router, pilotiq, PageClass, base);
204
- }
205
- // ── Theme editor ──────────────────────────────────────
206
- // Pulled out 2026-05-12 (Phase 3 of the routes.ts split).
207
- if (cfg.themeEditor) {
208
- registerThemeRoutes(router, pilotiq, base);
209
- }
174
+ // ── `Pilotiq.guard()` — panel-wide 401 layer ──────────
175
+ // Documented as the unauthenticated-request gate, but until 2026-05-21
176
+ // only `_uploads` consulted it every other route relied on
177
+ // `cfg.user` returning null + `R.canX(user, …)` defaulting to true,
178
+ // so an app that wired `guard(req => Auth.check())` but shipped any
179
+ // Resource without `canAccess` ended up with an unauthenticated,
180
+ // fully-readable admin panel. Wrap every core panel route in one
181
+ // group so the guard runs in front of every handler.
182
+ const guardMiddleware = async (req, res, next) => {
183
+ if (cfg.guard) {
184
+ const allowed = await cfg.guard(req);
185
+ if (!allowed) {
186
+ res.status(401);
187
+ if (wantsJson(req))
188
+ return res.json({ ok: false, error: 'Unauthorized' });
189
+ return res.send('Unauthorized');
190
+ }
191
+ }
192
+ return next();
193
+ };
194
+ router.group({ middleware: [guardMiddleware] }, () => {
195
+ // ── Panel-level sibling routes ────────────────────────
196
+ // Dashboard, _uploads, _widget, _search, _notifications.
197
+ // Pulled out 2026-05-12 (Phase 2 of the routes.ts split).
198
+ registerPanelRoutes(router, pilotiq, base);
199
+ // ── Resource routes ───────────────────────────────────
200
+ // List / view / create / edit / delete + soft-delete / actions /
201
+ // widgets / deferred-table / reorder / per-row editable cells / the
202
+ // four form-state companion endpoints / record sub-pages. Each
203
+ // Resource also fans out into its registered relation managers
204
+ // (depth-1 + depth-2). Pulled out 2026-05-12 (Phase 5 of the
205
+ // routes.ts split).
206
+ for (const R of cfg.resources) {
207
+ registerResourceRoutes(router, pilotiq, R, base, {
208
+ reorderable: reorderEnabled.has(R.getSlug()),
209
+ editable: editableEnabled.has(R.getSlug()),
210
+ });
211
+ }
212
+ // ── Globals (singletons — 2-segment, no /:id) ────────
213
+ // Pulled out 2026-05-12 (Phase 3 of the routes.ts split).
214
+ for (const G of cfg.globals) {
215
+ registerGlobalRoutes(router, pilotiq, G, base);
216
+ }
217
+ // ── Custom pages (2-segment, slug route) ──────────────
218
+ // Pulled out 2026-05-12 (Phase 3 of the routes.ts split).
219
+ for (const PageClass of cfg.pages) {
220
+ // The dashboard page lives at `${base}` (panel routes handle it);
221
+ // skip it here so we don't register a duplicate `${pageUrl}` route
222
+ // or a broken `${base}/` (when `slug = ''`).
223
+ if (cfg.dashboardPage === PageClass)
224
+ continue;
225
+ registerCustomPageRoutes(router, pilotiq, PageClass, base);
226
+ }
227
+ // ── Theme editor ──────────────────────────────────────
228
+ // Pulled out 2026-05-12 (Phase 3 of the routes.ts split).
229
+ if (cfg.themeEditor) {
230
+ registerThemeRoutes(router, pilotiq, base);
231
+ }
232
+ });
210
233
  // Plugin route hook — runs AFTER all core routes register so plugins
211
234
  // can mount their own HTTP surface alongside the panel's. Order
212
235
  // matches the registration order on `.use()` / `.plugins([…])`. Each
@@ -215,6 +238,11 @@ export function registerPilotiqRoutes(router, pilotiq) {
215
238
  // `_notifications`) is the recommended shape. Failures inside a
216
239
  // plugin's hook propagate — boot order is "register all core, then
217
240
  // each plugin in order"; a throw on hook N stops hooks N+1..N+M.
241
+ //
242
+ // Plugin routes mount OUTSIDE the guard group — plugins own their
243
+ // own auth posture (e.g. public webhooks, custom auth handshakes).
244
+ // Plugin authors that want the panel guard should consult
245
+ // `cfg.guard` themselves at the top of their handlers.
218
246
  for (const plugin of pilotiq.getPlugins()) {
219
247
  plugin.registerRoutes?.(router, pilotiq);
220
248
  }
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,8 @@ export { iconMap, resolveIconName } from './icon-map.js';
10
10
  export { colors, BASE_COLOR_NAMES, HUE_NAMES } from './colors.js';
11
11
  export { parseSeedToScale } from './generate-scale.js';
12
12
  export { migrateThemeOverrides } from './migrate.js';
13
+ export { prismaThemeStorage } from './storage.js';
14
+ export type { ThemeStorageAdapter, PanelGlobalDelegate, PrismaThemeStorageOptions, } from './storage.js';
13
15
  export type { ColorName, ColorScale, ColorStep } from './colors.js';
14
16
  export type { StylePreset, BaseColor, HueColor, ThemeColor, ChartColor, RadiusPreset, SpacingPreset, IconLibrary, ThemeFonts, ThemeConfig, ThemeMeta, PresetDefinition, } from './types.js';
15
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AACnF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAEpD,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACnE,YAAY,EACV,WAAW,EACX,SAAS,EACT,QAAQ,EACR,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,gBAAgB,GACjB,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AACnF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,cAAc,CAAA;AAErB,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACnE,YAAY,EACV,WAAW,EACX,SAAS,EACT,QAAQ,EACR,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,gBAAgB,GACjB,MAAM,YAAY,CAAA"}
@@ -10,4 +10,5 @@ export { iconMap, resolveIconName } from './icon-map.js';
10
10
  export { colors, BASE_COLOR_NAMES, HUE_NAMES } from './colors.js';
11
11
  export { parseSeedToScale } from './generate-scale.js';
12
12
  export { migrateThemeOverrides } from './migrate.js';
13
+ export { prismaThemeStorage } from './storage.js';
13
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AACnF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AACnF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,86 @@
1
+ import type { ThemeConfig } from './types.js';
2
+ /**
3
+ * Adapter that persists a panel's theme overrides — the JSON blob
4
+ * written when a user edits theme settings via the `themeEditor()`
5
+ * plugin and reloaded on next boot.
6
+ *
7
+ * The shipped implementation is `prismaThemeStorage`, which writes to
8
+ * the `panelGlobal` row created by `@rudderjs/orm-prisma`. Apps on a
9
+ * different ORM, key-value store, or filesystem can implement the
10
+ * three methods themselves.
11
+ *
12
+ * Contract:
13
+ *
14
+ * - `load()` returns `null` when no overrides have been persisted yet
15
+ * (fresh install). Throwing surfaces a configuration error to the
16
+ * caller — pilotiq does not swallow.
17
+ * - `save(overrides)` writes the blob verbatim. The next `load()` must
18
+ * return a deep-equal copy. Throwing surfaces to the route handler
19
+ * as a 500.
20
+ * - `clear()` deletes the row. Tolerating "not found" is the adapter's
21
+ * responsibility — `clear()` on an empty store is a no-op.
22
+ */
23
+ export interface ThemeStorageAdapter {
24
+ load(): Promise<Partial<ThemeConfig> | null>;
25
+ save(overrides: Partial<ThemeConfig>): Promise<void>;
26
+ clear(): Promise<void>;
27
+ }
28
+ /**
29
+ * Minimal Prisma surface used by `prismaThemeStorage`. Narrow enough
30
+ * to keep the import surface decoupled from `PrismaClient`'s generated
31
+ * types — apps swap in any client whose `panelGlobal` delegate matches
32
+ * this shape.
33
+ */
34
+ export interface PanelGlobalDelegate {
35
+ panelGlobal: {
36
+ findUnique(args: {
37
+ where: {
38
+ slug: string;
39
+ };
40
+ }): Promise<{
41
+ data: string | object | null;
42
+ } | null>;
43
+ upsert(args: {
44
+ where: {
45
+ slug: string;
46
+ };
47
+ update: {
48
+ data: string;
49
+ };
50
+ create: {
51
+ slug: string;
52
+ data: string;
53
+ };
54
+ }): Promise<unknown>;
55
+ delete(args: {
56
+ where: {
57
+ slug: string;
58
+ };
59
+ }): Promise<unknown>;
60
+ };
61
+ }
62
+ export interface PrismaThemeStorageOptions {
63
+ /** Row key written to `panelGlobal.slug`. Pass per-panel so multiple
64
+ * panels in the same app don't clobber each other. Typically
65
+ * `${panel.name}__theme`. */
66
+ slug: string;
67
+ }
68
+ /**
69
+ * Default storage adapter — writes JSON to the `panelGlobal` row keyed
70
+ * by `opts.slug`. The Prisma delegate is dependency-injected so consumers
71
+ * pick how to resolve it (e.g. `app.make('prisma')`, a direct import, a
72
+ * test stub).
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * import { Pilotiq } from '@pilotiq/pilotiq'
77
+ * import { themeEditor, prismaThemeStorage } from '@pilotiq/pilotiq/plugins'
78
+ *
79
+ * const adminPanel = Pilotiq.make('Admin')
80
+ * .use(themeEditor({
81
+ * storage: prismaThemeStorage(prisma, { slug: 'admin__theme' }),
82
+ * }))
83
+ * ```
84
+ */
85
+ export declare function prismaThemeStorage(prisma: PanelGlobalDelegate, opts: PrismaThemeStorageOptions): ThemeStorageAdapter;
86
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/theme/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,CAAA;IAC5C,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE;QACX,UAAU,CAAC,IAAI,EAAE;YAAE,KAAK,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,GAAG,OAAO,CAAC;YAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;SAAE,GAAG,IAAI,CAAC,CAAA;QAC/F,MAAM,CAAC,IAAI,EAAE;YACX,KAAK,EAAG;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,CAAA;YACxB,MAAM,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,CAAA;YACxB,MAAM,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,CAAA;SACvC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QACpB,MAAM,CAAC,IAAI,EAAE;YAAE,KAAK,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;KAC5D,CAAA;CACF;AAED,MAAM,WAAW,yBAAyB;IACxC;;kCAE8B;IAC9B,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,mBAAmB,EAC3B,IAAI,EAAI,yBAAyB,GAChC,mBAAmB,CAyBrB"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Default storage adapter — writes JSON to the `panelGlobal` row keyed
3
+ * by `opts.slug`. The Prisma delegate is dependency-injected so consumers
4
+ * pick how to resolve it (e.g. `app.make('prisma')`, a direct import, a
5
+ * test stub).
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { Pilotiq } from '@pilotiq/pilotiq'
10
+ * import { themeEditor, prismaThemeStorage } from '@pilotiq/pilotiq/plugins'
11
+ *
12
+ * const adminPanel = Pilotiq.make('Admin')
13
+ * .use(themeEditor({
14
+ * storage: prismaThemeStorage(prisma, { slug: 'admin__theme' }),
15
+ * }))
16
+ * ```
17
+ */
18
+ export function prismaThemeStorage(prisma, opts) {
19
+ const { slug } = opts;
20
+ return {
21
+ async load() {
22
+ const row = await prisma.panelGlobal.findUnique({ where: { slug } });
23
+ if (!row?.data)
24
+ return null;
25
+ const raw = typeof row.data === 'string' ? JSON.parse(row.data) : row.data;
26
+ return raw;
27
+ },
28
+ async save(overrides) {
29
+ const data = JSON.stringify(overrides);
30
+ await prisma.panelGlobal.upsert({
31
+ where: { slug },
32
+ update: { data },
33
+ create: { slug, data },
34
+ });
35
+ },
36
+ async clear() {
37
+ try {
38
+ await prisma.panelGlobal.delete({ where: { slug } });
39
+ }
40
+ catch (e) {
41
+ if (!isRecordNotFound(e))
42
+ throw e;
43
+ }
44
+ },
45
+ };
46
+ }
47
+ function isRecordNotFound(e) {
48
+ return typeof e === 'object'
49
+ && e !== null
50
+ && e.code === 'P2025';
51
+ }
52
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/theme/storage.ts"],"names":[],"mappings":"AAsDA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAA2B,EAC3B,IAAiC;IAEjC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAA;IACrB,OAAO;QACL,KAAK,CAAC,IAAI;YACR,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;YACpE,IAAI,CAAC,GAAG,EAAE,IAAI;gBAAE,OAAO,IAAI,CAAA;YAC3B,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAA;YAC1E,OAAO,GAA2B,CAAA;QACpC,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,SAAS;YAClB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;YACtC,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;gBAC9B,KAAK,EAAG,EAAE,IAAI,EAAE;gBAChB,MAAM,EAAE,EAAE,IAAI,EAAE;gBAChB,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;aACvB,CAAC,CAAA;QACJ,CAAC;QACD,KAAK,CAAC,KAAK;YACT,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;YACtD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;oBAAE,MAAM,CAAC,CAAA;YACnC,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAU;IAClC,OAAO,OAAO,CAAC,KAAK,QAAQ;WACvB,CAAC,KAAK,IAAI;WACT,CAAuB,CAAC,IAAI,KAAK,OAAO,CAAA;AAChD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pilotiq/pilotiq",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "description": "View-based admin panel for RudderJS",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Phase 5 perf sweep — covers the four hot-path changes that landed
3
+ * 2026-05-22:
4
+ *
5
+ * - 5b Per-user navigation-badge TTL cache (`Pilotiq.navigationBadgeTtl`)
6
+ * - 5c Map-based slug lookup (`Pilotiq.findResource/findGlobal/findPage`)
7
+ * - 5a Chunked import (`importFactory.runImport` honors `concurrency`)
8
+ *
9
+ * 5d (`policyGate`) is exercised indirectly by the existing routes /
10
+ * authorization tests — its contract is identical to the prior
11
+ * serial pair, just parallelized; no behavior change to assert here.
12
+ */
13
+ import { describe, it } from 'node:test'
14
+ import assert from 'node:assert/strict'
15
+
16
+ import { Pilotiq } from './Pilotiq.js'
17
+ import { Resource } from './Resource.js'
18
+ import { Global } from './Global.js'
19
+ import { Page } from './Page.js'
20
+ import { runImport } from './actions/importFactory.js'
21
+
22
+ // ─── Fixtures ─────────────────────────────────────────────────
23
+
24
+ class Articles extends Resource {
25
+ static override slug = 'articles'
26
+ static override label = 'Articles'
27
+ }
28
+ class Comments extends Resource {
29
+ static override slug = 'comments'
30
+ static override label = 'Comments'
31
+ }
32
+ class Settings extends Global {
33
+ static override slug = 'settings'
34
+ static override label = 'Settings'
35
+ }
36
+ class Branding extends Global {
37
+ static override slug = 'branding'
38
+ static override label = 'Branding'
39
+ }
40
+ class Reports extends Page {
41
+ static override slug = 'reports'
42
+ static override label = 'Reports'
43
+ }
44
+ class Health extends Page {
45
+ static override slug = 'health'
46
+ static override label = 'Health'
47
+ }
48
+
49
+ // ─── 5c — Map-based slug lookup ───────────────────────────────
50
+
51
+ describe('Pilotiq.find{Resource,Global,Page}() — Plan 5c', () => {
52
+ it('returns the matching class by slug', () => {
53
+ const p = Pilotiq.make('admin')
54
+ .resources([Articles, Comments])
55
+ .globals([Settings, Branding])
56
+ .pages([Reports, Health])
57
+ assert.equal(p.findResource('articles'), Articles)
58
+ assert.equal(p.findResource('comments'), Comments)
59
+ assert.equal(p.findGlobal('settings'), Settings)
60
+ assert.equal(p.findGlobal('branding'), Branding)
61
+ assert.equal(p.findPage('reports'), Reports)
62
+ assert.equal(p.findPage('health'), Health)
63
+ })
64
+
65
+ it('returns undefined for unknown slugs', () => {
66
+ const p = Pilotiq.make('admin').resources([Articles])
67
+ assert.equal(p.findResource('nope'), undefined)
68
+ assert.equal(p.findGlobal('nope'), undefined)
69
+ assert.equal(p.findPage('nope'), undefined)
70
+ })
71
+
72
+ it('invalidates the cache when .resources() is reassigned', () => {
73
+ const p = Pilotiq.make('admin').resources([Articles])
74
+ assert.equal(p.findResource('articles'), Articles)
75
+ assert.equal(p.findResource('comments'), undefined)
76
+ p.resources([Articles, Comments])
77
+ assert.equal(p.findResource('comments'), Comments)
78
+ })
79
+
80
+ it('invalidates the page cache when .pages() is reassigned', () => {
81
+ const p = Pilotiq.make('admin').pages([Reports])
82
+ assert.equal(p.findPage('reports'), Reports)
83
+ assert.equal(p.findPage('health'), undefined)
84
+ p.pages([Reports, Health])
85
+ assert.equal(p.findPage('health'), Health)
86
+ })
87
+
88
+ it('invalidates the page cache when .dashboard()/.profile() auto-append', () => {
89
+ class Dash extends Page {
90
+ static override slug = 'dash'
91
+ static override label = 'Dashboard'
92
+ }
93
+ const p = Pilotiq.make('admin')
94
+ assert.equal(p.findPage('dash'), undefined)
95
+ p.dashboard(Dash)
96
+ assert.equal(p.findPage('dash'), Dash)
97
+ })
98
+ })
99
+
100
+ // ─── 5b — Navigation badge TTL cache ──────────────────────────
101
+
102
+ describe('Pilotiq.navigationBadgeTtl() + resolveNavigationBadge() — Plan 5b', () => {
103
+ it('default TTL is 30s', () => {
104
+ const p = Pilotiq.make('admin')
105
+ assert.equal(p.getNavigationBadgeTtl(), 30_000)
106
+ })
107
+
108
+ it('navigationBadgeTtl(ms) overrides; clamps negatives to 0', () => {
109
+ const p = Pilotiq.make('admin').navigationBadgeTtl(5_000)
110
+ assert.equal(p.getNavigationBadgeTtl(), 5_000)
111
+ p.navigationBadgeTtl(-1)
112
+ assert.equal(p.getNavigationBadgeTtl(), 0)
113
+ })
114
+
115
+ it('navigationBadgeTtl(null) restores the default', () => {
116
+ const p = Pilotiq.make('admin').navigationBadgeTtl(1_000)
117
+ p.navigationBadgeTtl(null)
118
+ assert.equal(p.getNavigationBadgeTtl(), 30_000)
119
+ })
120
+
121
+ it('resolveNavigationBadge caches within TTL, busts on user change', async () => {
122
+ const p = Pilotiq.make('admin')
123
+ let calls = 0
124
+ const resolver = async () => { calls++; return String(calls) }
125
+
126
+ // First call: miss → resolver fires → returns '1'.
127
+ assert.equal(await p.resolveNavigationBadge('Articles', { id: 1 }, resolver), '1')
128
+ assert.equal(calls, 1)
129
+ // Same user + owner: hit → no new call → still '1'.
130
+ assert.equal(await p.resolveNavigationBadge('Articles', { id: 1 }, resolver), '1')
131
+ assert.equal(calls, 1)
132
+ // Different user: miss → resolver fires again.
133
+ assert.equal(await p.resolveNavigationBadge('Articles', { id: 2 }, resolver), '2')
134
+ assert.equal(calls, 2)
135
+ // Different owner, same user: separate cache slot.
136
+ assert.equal(await p.resolveNavigationBadge('Comments', { id: 1 }, resolver), '3')
137
+ assert.equal(calls, 3)
138
+ })
139
+
140
+ it('TTL of 0 disables caching entirely', async () => {
141
+ const p = Pilotiq.make('admin').navigationBadgeTtl(0)
142
+ let calls = 0
143
+ const resolver = async () => { calls++; return 'x' }
144
+ await p.resolveNavigationBadge('Articles', { id: 1 }, resolver)
145
+ await p.resolveNavigationBadge('Articles', { id: 1 }, resolver)
146
+ assert.equal(calls, 2)
147
+ })
148
+
149
+ it('caches undefined results (no need to keep re-resolving "no badge")', async () => {
150
+ const p = Pilotiq.make('admin')
151
+ let calls = 0
152
+ const resolver = async () => { calls++; return undefined }
153
+ assert.equal(await p.resolveNavigationBadge('Articles', null, resolver), undefined)
154
+ assert.equal(await p.resolveNavigationBadge('Articles', null, resolver), undefined)
155
+ assert.equal(calls, 1)
156
+ })
157
+
158
+ it('navigationBadgeTtl(ms) clears the cache', async () => {
159
+ const p = Pilotiq.make('admin')
160
+ let calls = 0
161
+ const resolver = async () => { calls++; return 'x' }
162
+ await p.resolveNavigationBadge('A', null, resolver)
163
+ assert.equal(calls, 1)
164
+ p.navigationBadgeTtl(60_000)
165
+ await p.resolveNavigationBadge('A', null, resolver)
166
+ assert.equal(calls, 2)
167
+ })
168
+
169
+ it('anonymous users share one cache slot', async () => {
170
+ const p = Pilotiq.make('admin')
171
+ let calls = 0
172
+ const resolver = async () => { calls++; return 'x' }
173
+ await p.resolveNavigationBadge('A', null, resolver)
174
+ await p.resolveNavigationBadge('A', undefined, resolver)
175
+ assert.equal(calls, 1)
176
+ })
177
+
178
+ it('falls back to JSON.stringify when user has no .id', async () => {
179
+ const p = Pilotiq.make('admin')
180
+ let calls = 0
181
+ const resolver = async () => { calls++; return 'x' }
182
+ await p.resolveNavigationBadge('A', { role: 'editor' }, resolver)
183
+ await p.resolveNavigationBadge('A', { role: 'editor' }, resolver)
184
+ assert.equal(calls, 1) // same JSON shape → cache hit
185
+ await p.resolveNavigationBadge('A', { role: 'admin' }, resolver)
186
+ assert.equal(calls, 2) // different JSON → miss
187
+ })
188
+ })
189
+
190
+ // ─── 5a — Chunked importFactory.runImport ─────────────────────
191
+
192
+ describe('importFactory.runImport — Plan 5a chunking', () => {
193
+ it('runs rows in chunks of `concurrency` and aggregates counts', async () => {
194
+ const created: string[] = []
195
+ let maxInFlight = 0
196
+ let inFlight = 0
197
+ const M = {
198
+ async create(row: { id: string }) {
199
+ inFlight++; if (inFlight > maxInFlight) maxInFlight = inFlight
200
+ await new Promise(r => setTimeout(r, 5))
201
+ inFlight--
202
+ created.push(row.id)
203
+ },
204
+ // unused for create-mode tests but the type wants them present
205
+ query() { return { where() { return { paginate: async () => ({ data: [] }) } } } },
206
+ async update() {},
207
+ }
208
+ const rows = Array.from({ length: 25 }, (_, i) => ({ id: `r${i}` }))
209
+ const summary = await runImport(rows, M, 'create', { concurrency: 5 }, { request: undefined })
210
+ assert.equal(summary.created, 25)
211
+ assert.equal(summary.errors.length, 0)
212
+ // With concurrency=5 we should see at least 4 in-flight at peak.
213
+ assert.ok(maxInFlight >= 4, `expected >=4 concurrent, saw ${maxInFlight}`)
214
+ // Never exceed the cap.
215
+ assert.ok(maxInFlight <= 5, `expected <=5 concurrent, saw ${maxInFlight}`)
216
+ })
217
+
218
+ it('preserves original-row indices in error messages despite chunking', async () => {
219
+ const M = {
220
+ async create(row: { id: string }) {
221
+ if (row.id === 'r2') throw new Error('boom')
222
+ },
223
+ query() { return { where() { return { paginate: async () => ({ data: [] }) } } } },
224
+ async update() {},
225
+ }
226
+ const rows = [{ id: 'r0' }, { id: 'r1' }, { id: 'r2' }, { id: 'r3' }]
227
+ const summary = await runImport(rows, M, 'create', { concurrency: 4 }, { request: undefined })
228
+ assert.equal(summary.created, 3)
229
+ assert.equal(summary.skipped, 1)
230
+ assert.equal(summary.errors.length, 1)
231
+ assert.equal(summary.errors[0]?.row, 3) // 1-based, original index 2 → row 3
232
+ assert.match(summary.errors[0]?.message ?? '', /boom/)
233
+ })
234
+
235
+ it('defaults to concurrency 10 when unset', async () => {
236
+ let maxInFlight = 0
237
+ let inFlight = 0
238
+ const M = {
239
+ async create() {
240
+ inFlight++; if (inFlight > maxInFlight) maxInFlight = inFlight
241
+ await new Promise(r => setTimeout(r, 3))
242
+ inFlight--
243
+ },
244
+ query() { return { where() { return { paginate: async () => ({ data: [] }) } } } },
245
+ async update() {},
246
+ }
247
+ const rows = Array.from({ length: 30 }, () => ({}))
248
+ await runImport(rows, M, 'create', {}, { request: undefined })
249
+ assert.ok(maxInFlight <= 10, `expected <=10 concurrent, saw ${maxInFlight}`)
250
+ assert.ok(maxInFlight >= 5, `expected >=5 concurrent under default, saw ${maxInFlight}`)
251
+ })
252
+ })
@@ -62,6 +62,10 @@ function makeStubRouter(): Router & { _calls: Array<{ method: string; path: stri
62
62
  put: (path: string) => noop(path),
63
63
  delete: (path: string) => noop(path),
64
64
  patch: (path: string) => noop(path),
65
+ // `router.group(opts, fn)` runs `fn()` synchronously inside its
66
+ // scope. Stub mirrors that — `Pilotiq.guard()` middleware doesn't
67
+ // touch the stub, only `fn()` matters.
68
+ group: (_opts: unknown, fn: () => void) => { fn() },
65
69
  _calls: calls,
66
70
  }
67
71
  return stub