@pilotiq/pilotiq 0.1.0 → 0.3.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 (108) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +14 -0
  3. package/CLAUDE.md +6 -5
  4. package/dist/Pilotiq.d.ts +20 -1
  5. package/dist/Pilotiq.d.ts.map +1 -1
  6. package/dist/Pilotiq.js.map +1 -1
  7. package/dist/actions/Action.d.ts +25 -0
  8. package/dist/actions/Action.d.ts.map +1 -1
  9. package/dist/actions/Action.js +25 -0
  10. package/dist/actions/Action.js.map +1 -1
  11. package/dist/elements/dispatchForm.d.ts +0 -14
  12. package/dist/elements/dispatchForm.d.ts.map +1 -1
  13. package/dist/elements/dispatchForm.js +28 -0
  14. package/dist/elements/dispatchForm.js.map +1 -1
  15. package/dist/fields/BuilderField.d.ts +27 -1
  16. package/dist/fields/BuilderField.d.ts.map +1 -1
  17. package/dist/fields/BuilderField.js +36 -1
  18. package/dist/fields/BuilderField.js.map +1 -1
  19. package/dist/fields/FileUploadField.d.ts +65 -0
  20. package/dist/fields/FileUploadField.d.ts.map +1 -1
  21. package/dist/fields/FileUploadField.js +72 -0
  22. package/dist/fields/FileUploadField.js.map +1 -1
  23. package/dist/fields/RepeaterField.d.ts +34 -1
  24. package/dist/fields/RepeaterField.d.ts.map +1 -1
  25. package/dist/fields/RepeaterField.js +43 -1
  26. package/dist/fields/RepeaterField.js.map +1 -1
  27. package/dist/fields/RowButton.d.ts +9 -2
  28. package/dist/fields/RowButton.d.ts.map +1 -1
  29. package/dist/fields/TextField.d.ts +106 -0
  30. package/dist/fields/TextField.d.ts.map +1 -1
  31. package/dist/fields/TextField.js +115 -0
  32. package/dist/fields/TextField.js.map +1 -1
  33. package/dist/filters/queryBuilder/Constraint.d.ts +1 -1
  34. package/dist/filters/queryBuilder/Constraint.d.ts.map +1 -1
  35. package/dist/filters/queryBuilder/TextConstraint.d.ts.map +1 -1
  36. package/dist/filters/queryBuilder/TextConstraint.js +2 -3
  37. package/dist/filters/queryBuilder/TextConstraint.js.map +1 -1
  38. package/dist/orm/modelDefaults.d.ts +1 -1
  39. package/dist/orm/modelDefaults.d.ts.map +1 -1
  40. package/dist/react/SchemaRenderer.d.ts.map +1 -1
  41. package/dist/react/SchemaRenderer.js +108 -7
  42. package/dist/react/SchemaRenderer.js.map +1 -1
  43. package/dist/react/fields/BuilderInput.d.ts.map +1 -1
  44. package/dist/react/fields/BuilderInput.js +32 -3
  45. package/dist/react/fields/BuilderInput.js.map +1 -1
  46. package/dist/react/fields/FieldShell.d.ts +9 -1
  47. package/dist/react/fields/FieldShell.d.ts.map +1 -1
  48. package/dist/react/fields/FieldShell.js +4 -3
  49. package/dist/react/fields/FieldShell.js.map +1 -1
  50. package/dist/react/fields/FileUploadInput.d.ts +17 -4
  51. package/dist/react/fields/FileUploadInput.d.ts.map +1 -1
  52. package/dist/react/fields/FileUploadInput.js +204 -25
  53. package/dist/react/fields/FileUploadInput.js.map +1 -1
  54. package/dist/react/fields/RepeaterInput.d.ts.map +1 -1
  55. package/dist/react/fields/RepeaterInput.js +33 -2
  56. package/dist/react/fields/RepeaterInput.js.map +1 -1
  57. package/dist/react/fields/TextLikeInput.d.ts +5 -1
  58. package/dist/react/fields/TextLikeInput.d.ts.map +1 -1
  59. package/dist/react/fields/TextLikeInput.js +17 -2
  60. package/dist/react/fields/TextLikeInput.js.map +1 -1
  61. package/dist/react/fields/rowChromeButton.d.ts +24 -5
  62. package/dist/react/fields/rowChromeButton.d.ts.map +1 -1
  63. package/dist/react/fields/rowChromeButton.js +51 -8
  64. package/dist/react/fields/rowChromeButton.js.map +1 -1
  65. package/dist/react/fields/textInputControls.d.ts +47 -0
  66. package/dist/react/fields/textInputControls.d.ts.map +1 -0
  67. package/dist/react/fields/textInputControls.js +134 -0
  68. package/dist/react/fields/textInputControls.js.map +1 -0
  69. package/dist/routes.d.ts.map +1 -1
  70. package/dist/routes.js +32 -1
  71. package/dist/routes.js.map +1 -1
  72. package/dist/schema/Alert.d.ts +58 -0
  73. package/dist/schema/Alert.d.ts.map +1 -1
  74. package/dist/schema/Alert.js +68 -1
  75. package/dist/schema/Alert.js.map +1 -1
  76. package/dist/schema/resolveSchema.d.ts.map +1 -1
  77. package/dist/schema/resolveSchema.js +32 -0
  78. package/dist/schema/resolveSchema.js.map +1 -1
  79. package/package.json +12 -11
  80. package/src/Pilotiq.test.ts +78 -0
  81. package/src/Pilotiq.ts +20 -1
  82. package/src/actions/Action.test.ts +47 -0
  83. package/src/actions/Action.ts +35 -0
  84. package/src/elements/dispatchForm.ts +28 -0
  85. package/src/fields/BuilderField.ts +38 -1
  86. package/src/fields/FileUploadField.test.ts +46 -0
  87. package/src/fields/FileUploadField.ts +90 -2
  88. package/src/fields/RepeaterField.ts +45 -1
  89. package/src/fields/RowButton.test.ts +70 -0
  90. package/src/fields/RowButton.ts +11 -1
  91. package/src/fields/TextField.test.ts +168 -0
  92. package/src/fields/TextField.ts +141 -1
  93. package/src/filters/QueryBuilderFilter.test.ts +18 -0
  94. package/src/filters/queryBuilder/Constraint.ts +1 -1
  95. package/src/filters/queryBuilder/TextConstraint.ts +5 -6
  96. package/src/orm/modelDefaults.ts +1 -1
  97. package/src/react/SchemaRenderer.tsx +222 -14
  98. package/src/react/fields/BuilderInput.tsx +37 -0
  99. package/src/react/fields/FieldShell.tsx +13 -2
  100. package/src/react/fields/FileUploadInput.tsx +516 -85
  101. package/src/react/fields/RepeaterInput.tsx +39 -0
  102. package/src/react/fields/TextLikeInput.tsx +22 -2
  103. package/src/react/fields/rowChromeButton.tsx +102 -6
  104. package/src/react/fields/textInputControls.tsx +238 -0
  105. package/src/routes.ts +33 -1
  106. package/src/schema/Alert.test.ts +46 -0
  107. package/src/schema/Alert.ts +90 -8
  108. package/src/schema/resolveSchema.ts +32 -0
@@ -0,0 +1,134 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useCallback } from 'react';
3
+ import { useToast } from '../Toaster.js';
4
+ /** `renderAction(meta)` is supplied by the caller (SchemaRenderer's
5
+ * `renderElement`) to avoid an import cycle between the controls
6
+ * module and the main schema renderer. */
7
+ export function useTextInputControls(el, name, renderAction) {
8
+ const isPassword = el['password'] === true;
9
+ const isRevealable = el['revealable'] === true;
10
+ const isCopyable = el['copyable'] === true;
11
+ const copyMessage = el['copyMessage'] ?? 'Copied!';
12
+ const mask = el['mask'];
13
+ const prefixAct = el['prefixAction'];
14
+ const suffixAct = el['suffixAction'];
15
+ const [revealed, setRevealed] = useState(false);
16
+ const inputId = name;
17
+ const onCopy = useCopyHandler(inputId, copyMessage);
18
+ const type = isPassword && !revealed ? 'password' : 'text';
19
+ const beforeNodes = [];
20
+ if (prefixAct)
21
+ beforeNodes.push(_jsx("div", { className: "shrink-0", children: renderAction(prefixAct) }, "pre-act"));
22
+ const afterNodes = [];
23
+ if (isCopyable)
24
+ afterNodes.push(_jsx(CopyButton, { onCopy: onCopy }, "copy"));
25
+ if (isRevealable && isPassword) {
26
+ afterNodes.push(_jsx(RevealToggle, { revealed: revealed, onToggle: () => setRevealed(v => !v) }, "reveal"));
27
+ }
28
+ if (suffixAct)
29
+ afterNodes.push(_jsx("div", { className: "shrink-0", children: renderAction(suffixAct) }, "suf-act"));
30
+ const applyMask = useCallback((value) => {
31
+ if (!mask)
32
+ return value;
33
+ return formatWithMask(value, mask);
34
+ }, [mask]);
35
+ return {
36
+ before: beforeNodes.length > 0 ? _jsx(_Fragment, { children: beforeNodes }) : null,
37
+ after: afterNodes.length > 0 ? _jsx(_Fragment, { children: afterNodes }) : null,
38
+ type,
39
+ applyMask,
40
+ };
41
+ }
42
+ /**
43
+ * Format `raw` against `mask` using the documented alphabet. Literals
44
+ * in the mask render verbatim and consume no source character; pattern
45
+ * tokens consume the next matching source character (skipping
46
+ * mismatches so the user can paste an already-formatted value and have
47
+ * it re-format cleanly).
48
+ */
49
+ export function formatWithMask(raw, mask) {
50
+ let out = '';
51
+ let r = 0;
52
+ for (let m = 0; m < mask.length; m++) {
53
+ const token = mask[m];
54
+ const isPattern = token === '9' || token === 'a' || token === '*';
55
+ if (isPattern) {
56
+ if (r >= raw.length)
57
+ break;
58
+ // Advance through `raw` until we find a matching character.
59
+ while (r < raw.length) {
60
+ const ch = raw[r];
61
+ const ok = token === '9'
62
+ ? /[0-9]/.test(ch)
63
+ : token === 'a'
64
+ ? /[A-Za-z]/.test(ch)
65
+ : true;
66
+ r++;
67
+ if (ok) {
68
+ out += ch;
69
+ break;
70
+ }
71
+ }
72
+ }
73
+ else {
74
+ // Literal character — emit even when raw is exhausted, so a
75
+ // partially-typed value still shows the upcoming chrome
76
+ // (e.g. `(415) ` after the user types three digits). Consume the
77
+ // matching raw char if present so a paste of the already-formatted
78
+ // value doesn't double up.
79
+ out += token;
80
+ if (raw[r] === token)
81
+ r++;
82
+ }
83
+ }
84
+ return out;
85
+ }
86
+ function useCopyHandler(inputId, message) {
87
+ const { notify } = useToast();
88
+ return () => {
89
+ if (typeof document === 'undefined')
90
+ return;
91
+ const el = document.getElementById(inputId);
92
+ if (!el)
93
+ return;
94
+ const value = el.value;
95
+ const writeText = navigator?.clipboard?.writeText?.bind(navigator.clipboard);
96
+ if (writeText) {
97
+ writeText(value).then(() => notify({ type: 'success', title: message, duration: 2000 }), () => notify({ type: 'error', title: 'Copy failed' }));
98
+ }
99
+ else {
100
+ // Fallback: select + execCommand. Modern browsers all expose
101
+ // navigator.clipboard, so this is rare-path.
102
+ el.select();
103
+ try {
104
+ document.execCommand('copy');
105
+ notify({ type: 'success', title: message, duration: 2000 });
106
+ }
107
+ catch {
108
+ notify({ type: 'error', title: 'Copy failed' });
109
+ }
110
+ el.setSelectionRange?.(0, 0);
111
+ }
112
+ };
113
+ }
114
+ function ChromeButton({ onClick, ariaLabel, children, autoFocus }) {
115
+ return (_jsx("button", { type: "button", tabIndex: -1, onClick: (e) => { e.preventDefault(); onClick(e); }, "aria-label": ariaLabel, className: "inline-flex items-center justify-center rounded-md size-8 text-muted-foreground hover:bg-accent hover:text-accent-foreground shrink-0", autoFocus: autoFocus, children: children }));
116
+ }
117
+ function CopyButton({ onCopy }) {
118
+ return (_jsx(ChromeButton, { onClick: onCopy, ariaLabel: "Copy", children: _jsx(CopyIcon, { className: "size-4" }) }));
119
+ }
120
+ function RevealToggle({ revealed, onToggle }) {
121
+ return (_jsx(ChromeButton, { onClick: onToggle, ariaLabel: revealed ? 'Hide value' : 'Show value', children: revealed ? _jsx(EyeOffIcon, { className: "size-4" }) : _jsx(EyeIcon, { className: "size-4" }) }));
122
+ }
123
+ // ─── Inline icon SVGs (avoids pulling lucide-react import into this file
124
+ // without checking it's already a dep — keeps the bundle stable). ────
125
+ function CopyIcon(props) {
126
+ return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [_jsx("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }), _jsx("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })] }));
127
+ }
128
+ function EyeIcon(props) {
129
+ return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [_jsx("path", { d: "M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" }), _jsx("circle", { cx: "12", cy: "12", r: "3" })] }));
130
+ }
131
+ function EyeOffIcon(props) {
132
+ return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [_jsx("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), _jsx("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), _jsx("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), _jsx("line", { x1: "2", x2: "22", y1: "2", y2: "22" })] }));
133
+ }
134
+ //# sourceMappingURL=textInputControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textInputControls.js","sourceRoot":"","sources":["../../../src/react/fields/textInputControls.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAG9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAEzC,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AA4iBtF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GACf,IAAI,CAmoFN;AAGD,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAC3F,YAAY,EAAE,IAAI,EAAE,CAAA"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAG9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAEzC,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAgkBtF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GACf,IAAI,CA+oFN;AAGD,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAC3F,YAAY,EAAE,IAAI,EAAE,CAAA"}
package/dist/routes.js CHANGED
@@ -376,9 +376,29 @@ async function handleUploadRequest(req, res, pilotiq) {
376
376
  return res.json({ ok: false, error: `File exceeds ${maxSize} bytes` });
377
377
  }
378
378
  }
379
+ // Server-side resize via @rudderjs/image (optional peer dep)
380
+ const resizeWidthStr = typeof body['resize_width'] === 'string' ? body['resize_width'] : '';
381
+ const resizeHeightStr = typeof body['resize_height'] === 'string' ? body['resize_height'] : '';
382
+ let uploadFile = file;
383
+ if (resizeWidthStr && resizeHeightStr) {
384
+ const w = Number(resizeWidthStr);
385
+ const h = Number(resizeHeightStr);
386
+ if (Number.isFinite(w) && w > 0 && Number.isFinite(h) && h > 0) {
387
+ try {
388
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
389
+ const pkg = await import('@rudderjs/image');
390
+ const buf = await pkg.image(file).resize(w, h).format('webp').toBuffer();
391
+ const baseName = file.name.replace(/\.[^.]+$/, '');
392
+ uploadFile = new File([buf.buffer], `${baseName}.webp`, { type: 'image/webp' });
393
+ }
394
+ catch {
395
+ // @rudderjs/image not installed or resize failed — fall through with original file
396
+ }
397
+ }
398
+ }
379
399
  try {
380
400
  const result = await cfg.uploads.adapter.put({
381
- file,
401
+ file: uploadFile,
382
402
  ...(directory ? { directory } : {}),
383
403
  fieldName,
384
404
  });
@@ -3109,6 +3129,17 @@ export function registerPilotiqRoutes(router, pilotiq) {
3109
3129
  return res.json({ ok: true });
3110
3130
  });
3111
3131
  }
3132
+ // Plugin route hook — runs AFTER all core routes register so plugins
3133
+ // can mount their own HTTP surface alongside the panel's. Order
3134
+ // matches the registration order on `.use()` / `.plugins([…])`. Each
3135
+ // plugin owns its own URL convention; pilotiq's underscore-prefixed
3136
+ // sibling-route precedent (`_search`, `_uploads`, `_widget`,
3137
+ // `_notifications`) is the recommended shape. Failures inside a
3138
+ // plugin's hook propagate — boot order is "register all core, then
3139
+ // each plugin in order"; a throw on hook N stops hooks N+1..N+M.
3140
+ for (const plugin of pilotiq.getPlugins()) {
3141
+ plugin.registerRoutes?.(router, pilotiq);
3142
+ }
3112
3143
  }
3113
3144
  // ─── Lifecycle helpers exported for tests ────────────────
3114
3145
  export { dispatchFormSubmit, findForms, selectForm };