@ai-matrx/kit 0.5.1 → 0.5.2

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.
@@ -57,7 +57,8 @@ function treeContainsComponent(node, Component) {
57
57
  (child) => treeContainsComponent(child, Component)
58
58
  );
59
59
  }
60
- if (typeof process !== "undefined" && true) {
60
+ const runtimeProcess = globalThis.process;
61
+ if (runtimeProcess?.env?.NODE_ENV !== "production") {
61
62
  const keys = typeof node === "object" ? ` with keys {${Object.keys(node).join(", ")}}` : "";
62
63
  console.error(
63
64
  `[treeContainsComponent] A non-renderable value${keys} is being passed as a React child. React will throw 'Objects are not valid as a React child' at the real render site. Stringify it (e.g. JSON.stringify) before rendering.`,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react-tree.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/react-tree — safe React children-tree scanning.\n *\n * Ported from matrx-frontend `lib/react/treeContainsComponent.ts`; this\n * subpath is the ONE home of the scanner inside the kit (the `/confirm`\n * subpath's alert-dialog imports it from here — no duplicate bodies).\n *\n * Two deliberate divergences from the frontend original, both documented:\n * - the dev-mode scream checks `typeof process` first, since this package may\n * load in an unbundled browser context where `process` is undefined;\n * - a React PORTAL child (`createPortal(...)` passed as a child) is a valid\n * React child, but it is not an element, an iterable, or a primitive — the\n * original fell through to the non-renderable branch, screamed a false\n * positive in dev, and skipped the portal's content. Portals are now\n * recognized and their children traversed.\n */\n\nimport * as React from \"react\";\n\nconst REACT_PORTAL_TYPE = Symbol.for(\"react.portal\");\n\n/**\n * Returns true if `Component` appears anywhere in the React element tree under\n * `node`. Used to detect optional a11y children (e.g. DialogDescription)\n * without rendering duplicates.\n *\n * DEFENSIVE + LOUD. A non-renderable node — a plain object or function passed\n * as a React child — is a real bug: React throws \"Objects are not valid as a\n * React child\" the instant it renders one. This a11y probe must NOT be the\n * crash site. `React.Children.toArray` would throw HERE, producing a trace that\n * points at the dialog primitive instead of the component that leaked the\n * object (this misdirection has burned real debugging hours). So we walk the\n * tree by hand, SKIP any non-renderable node, and scream in dev with its keys —\n * then let React report the defect at the true render site with the offending\n * component in the stack. For every VALID tree the result is identical to the\n * old `React.Children.toArray(node).some(...)`.\n */\nexport function treeContainsComponent(\n node: React.ReactNode,\n Component: React.ElementType,\n): boolean {\n if (node == null || typeof node === \"boolean\") return false;\n\n if (Array.isArray(node)) {\n return node.some((child) => treeContainsComponent(child, Component));\n }\n\n if (React.isValidElement(node)) {\n if (node.type === Component) return true;\n const props = node.props as { children?: React.ReactNode };\n return props.children != null\n ? treeContainsComponent(props.children, Component)\n : false;\n }\n\n // Strings / numbers are valid leaf children but never the Component.\n if (typeof node === \"string\" || typeof node === \"number\") return false;\n\n // A portal is a valid child that is NOT an element: traverse its content.\n if (\n typeof node === \"object\" &&\n (node as { $$typeof?: unknown }).$$typeof === REACT_PORTAL_TYPE\n ) {\n return treeContainsComponent(\n (node as { children?: React.ReactNode }).children,\n Component,\n );\n }\n\n // Non-array iterables (Set, Map, generator) are valid React children — React\n // supports them — so traverse rather than reject.\n if (typeof node === \"object\" && Symbol.iterator in node) {\n return Array.from(node as Iterable<React.ReactNode>).some((child) =>\n treeContainsComponent(child, Component),\n );\n }\n\n // Anything else (a raw object, a function) is NOT a valid React child. React\n // will throw when it renders this; we must not throw first and hide the cause.\n if (\n typeof process !== \"undefined\" &&\n process.env.NODE_ENV !== \"production\"\n ) {\n const keys =\n typeof node === \"object\"\n ? ` with keys {${Object.keys(node).join(\", \")}}`\n : \"\";\n console.error(\n `[treeContainsComponent] A non-renderable value${keys} is being passed as a React child. ` +\n \"React will throw 'Objects are not valid as a React child' at the real render site. \" +\n \"Stringify it (e.g. JSON.stringify) before rendering.\",\n node,\n );\n }\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,YAAuB;AAEvB,IAAM,oBAAoB,uBAAO,IAAI,cAAc;AAkB5C,SAAS,sBACd,MACA,WACS;AACT,MAAI,QAAQ,QAAQ,OAAO,SAAS,UAAW,QAAO;AAEtD,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,KAAK,CAAC,UAAU,sBAAsB,OAAO,SAAS,CAAC;AAAA,EACrE;AAEA,MAAU,qBAAe,IAAI,GAAG;AAC9B,QAAI,KAAK,SAAS,UAAW,QAAO;AACpC,UAAM,QAAQ,KAAK;AACnB,WAAO,MAAM,YAAY,OACrB,sBAAsB,MAAM,UAAU,SAAS,IAC/C;AAAA,EACN;AAGA,MAAI,OAAO,SAAS,YAAY,OAAO,SAAS,SAAU,QAAO;AAGjE,MACE,OAAO,SAAS,YACf,KAAgC,aAAa,mBAC9C;AACA,WAAO;AAAA,MACJ,KAAwC;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAIA,MAAI,OAAO,SAAS,YAAY,OAAO,YAAY,MAAM;AACvD,WAAO,MAAM,KAAK,IAAiC,EAAE;AAAA,MAAK,CAAC,UACzD,sBAAsB,OAAO,SAAS;AAAA,IACxC;AAAA,EACF;AAIA,MACE,OAAO,YAAY,eACnB,MACA;AACA,UAAM,OACJ,OAAO,SAAS,WACZ,eAAe,OAAO,KAAK,IAAI,EAAE,KAAK,IAAI,CAAC,MAC3C;AACN,YAAQ;AAAA,MACN,iDAAiD,IAAI;AAAA,MAGrD;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/react-tree.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/react-tree — safe React children-tree scanning.\n *\n * Ported from matrx-frontend `lib/react/treeContainsComponent.ts`; this\n * subpath is the ONE home of the scanner inside the kit (the `/confirm`\n * subpath's alert-dialog imports it from here — no duplicate bodies).\n *\n * Two deliberate divergences from the frontend original, both documented:\n * - the dev-mode scream checks `typeof process` first, since this package may\n * load in an unbundled browser context where `process` is undefined;\n * - a React PORTAL child (`createPortal(...)` passed as a child) is a valid\n * React child, but it is not an element, an iterable, or a primitive — the\n * original fell through to the non-renderable branch, screamed a false\n * positive in dev, and skipped the portal's content. Portals are now\n * recognized and their children traversed.\n */\n\nimport * as React from \"react\";\n\nconst REACT_PORTAL_TYPE = Symbol.for(\"react.portal\");\n\n/**\n * Returns true if `Component` appears anywhere in the React element tree under\n * `node`. Used to detect optional a11y children (e.g. DialogDescription)\n * without rendering duplicates.\n *\n * DEFENSIVE + LOUD. A non-renderable node — a plain object or function passed\n * as a React child — is a real bug: React throws \"Objects are not valid as a\n * React child\" the instant it renders one. This a11y probe must NOT be the\n * crash site. `React.Children.toArray` would throw HERE, producing a trace that\n * points at the dialog primitive instead of the component that leaked the\n * object (this misdirection has burned real debugging hours). So we walk the\n * tree by hand, SKIP any non-renderable node, and scream in dev with its keys —\n * then let React report the defect at the true render site with the offending\n * component in the stack. For every VALID tree the result is identical to the\n * old `React.Children.toArray(node).some(...)`.\n */\nexport function treeContainsComponent(\n node: React.ReactNode,\n Component: React.ElementType,\n): boolean {\n if (node == null || typeof node === \"boolean\") return false;\n\n if (Array.isArray(node)) {\n return node.some((child) => treeContainsComponent(child, Component));\n }\n\n if (React.isValidElement(node)) {\n if (node.type === Component) return true;\n const props = node.props as { children?: React.ReactNode };\n return props.children != null\n ? treeContainsComponent(props.children, Component)\n : false;\n }\n\n // Strings / numbers are valid leaf children but never the Component.\n if (typeof node === \"string\" || typeof node === \"number\") return false;\n\n // A portal is a valid child that is NOT an element: traverse its content.\n if (\n typeof node === \"object\" &&\n (node as { $$typeof?: unknown }).$$typeof === REACT_PORTAL_TYPE\n ) {\n return treeContainsComponent(\n (node as { children?: React.ReactNode }).children,\n Component,\n );\n }\n\n // Non-array iterables (Set, Map, generator) are valid React children — React\n // supports them — so traverse rather than reject.\n if (typeof node === \"object\" && Symbol.iterator in node) {\n return Array.from(node as Iterable<React.ReactNode>).some((child) =>\n treeContainsComponent(child, Component),\n );\n }\n\n // Anything else (a raw object, a function) is NOT a valid React child. React\n // will throw when it renders this; we must not throw first and hide the cause.\n const runtimeProcess = (\n globalThis as { process?: { env?: { NODE_ENV?: string } } }\n ).process;\n if (runtimeProcess?.env?.NODE_ENV !== \"production\") {\n const keys =\n typeof node === \"object\"\n ? ` with keys {${Object.keys(node).join(\", \")}}`\n : \"\";\n console.error(\n `[treeContainsComponent] A non-renderable value${keys} is being passed as a React child. ` +\n \"React will throw 'Objects are not valid as a React child' at the real render site. \" +\n \"Stringify it (e.g. JSON.stringify) before rendering.\",\n node,\n );\n }\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,YAAuB;AAEvB,IAAM,oBAAoB,uBAAO,IAAI,cAAc;AAkB5C,SAAS,sBACd,MACA,WACS;AACT,MAAI,QAAQ,QAAQ,OAAO,SAAS,UAAW,QAAO;AAEtD,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,KAAK,CAAC,UAAU,sBAAsB,OAAO,SAAS,CAAC;AAAA,EACrE;AAEA,MAAU,qBAAe,IAAI,GAAG;AAC9B,QAAI,KAAK,SAAS,UAAW,QAAO;AACpC,UAAM,QAAQ,KAAK;AACnB,WAAO,MAAM,YAAY,OACrB,sBAAsB,MAAM,UAAU,SAAS,IAC/C;AAAA,EACN;AAGA,MAAI,OAAO,SAAS,YAAY,OAAO,SAAS,SAAU,QAAO;AAGjE,MACE,OAAO,SAAS,YACf,KAAgC,aAAa,mBAC9C;AACA,WAAO;AAAA,MACJ,KAAwC;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAIA,MAAI,OAAO,SAAS,YAAY,OAAO,YAAY,MAAM;AACvD,WAAO,MAAM,KAAK,IAAiC,EAAE;AAAA,MAAK,CAAC,UACzD,sBAAsB,OAAO,SAAS;AAAA,IACxC;AAAA,EACF;AAIA,QAAM,iBACJ,WACA;AACF,MAAI,gBAAgB,KAAK,aAAa,cAAc;AAClD,UAAM,OACJ,OAAO,SAAS,WACZ,eAAe,OAAO,KAAK,IAAI,EAAE,KAAK,IAAI,CAAC,MAC3C;AACN,YAAQ;AAAA,MACN,iDAAiD,IAAI;AAAA,MAGrD;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
@@ -23,7 +23,8 @@ function treeContainsComponent(node, Component) {
23
23
  (child) => treeContainsComponent(child, Component)
24
24
  );
25
25
  }
26
- if (typeof process !== "undefined" && true) {
26
+ const runtimeProcess = globalThis.process;
27
+ if (runtimeProcess?.env?.NODE_ENV !== "production") {
27
28
  const keys = typeof node === "object" ? ` with keys {${Object.keys(node).join(", ")}}` : "";
28
29
  console.error(
29
30
  `[treeContainsComponent] A non-renderable value${keys} is being passed as a React child. React will throw 'Objects are not valid as a React child' at the real render site. Stringify it (e.g. JSON.stringify) before rendering.`,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react-tree.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/react-tree — safe React children-tree scanning.\n *\n * Ported from matrx-frontend `lib/react/treeContainsComponent.ts`; this\n * subpath is the ONE home of the scanner inside the kit (the `/confirm`\n * subpath's alert-dialog imports it from here — no duplicate bodies).\n *\n * Two deliberate divergences from the frontend original, both documented:\n * - the dev-mode scream checks `typeof process` first, since this package may\n * load in an unbundled browser context where `process` is undefined;\n * - a React PORTAL child (`createPortal(...)` passed as a child) is a valid\n * React child, but it is not an element, an iterable, or a primitive — the\n * original fell through to the non-renderable branch, screamed a false\n * positive in dev, and skipped the portal's content. Portals are now\n * recognized and their children traversed.\n */\n\nimport * as React from \"react\";\n\nconst REACT_PORTAL_TYPE = Symbol.for(\"react.portal\");\n\n/**\n * Returns true if `Component` appears anywhere in the React element tree under\n * `node`. Used to detect optional a11y children (e.g. DialogDescription)\n * without rendering duplicates.\n *\n * DEFENSIVE + LOUD. A non-renderable node — a plain object or function passed\n * as a React child — is a real bug: React throws \"Objects are not valid as a\n * React child\" the instant it renders one. This a11y probe must NOT be the\n * crash site. `React.Children.toArray` would throw HERE, producing a trace that\n * points at the dialog primitive instead of the component that leaked the\n * object (this misdirection has burned real debugging hours). So we walk the\n * tree by hand, SKIP any non-renderable node, and scream in dev with its keys —\n * then let React report the defect at the true render site with the offending\n * component in the stack. For every VALID tree the result is identical to the\n * old `React.Children.toArray(node).some(...)`.\n */\nexport function treeContainsComponent(\n node: React.ReactNode,\n Component: React.ElementType,\n): boolean {\n if (node == null || typeof node === \"boolean\") return false;\n\n if (Array.isArray(node)) {\n return node.some((child) => treeContainsComponent(child, Component));\n }\n\n if (React.isValidElement(node)) {\n if (node.type === Component) return true;\n const props = node.props as { children?: React.ReactNode };\n return props.children != null\n ? treeContainsComponent(props.children, Component)\n : false;\n }\n\n // Strings / numbers are valid leaf children but never the Component.\n if (typeof node === \"string\" || typeof node === \"number\") return false;\n\n // A portal is a valid child that is NOT an element: traverse its content.\n if (\n typeof node === \"object\" &&\n (node as { $$typeof?: unknown }).$$typeof === REACT_PORTAL_TYPE\n ) {\n return treeContainsComponent(\n (node as { children?: React.ReactNode }).children,\n Component,\n );\n }\n\n // Non-array iterables (Set, Map, generator) are valid React children — React\n // supports them — so traverse rather than reject.\n if (typeof node === \"object\" && Symbol.iterator in node) {\n return Array.from(node as Iterable<React.ReactNode>).some((child) =>\n treeContainsComponent(child, Component),\n );\n }\n\n // Anything else (a raw object, a function) is NOT a valid React child. React\n // will throw when it renders this; we must not throw first and hide the cause.\n if (\n typeof process !== \"undefined\" &&\n process.env.NODE_ENV !== \"production\"\n ) {\n const keys =\n typeof node === \"object\"\n ? ` with keys {${Object.keys(node).join(\", \")}}`\n : \"\";\n console.error(\n `[treeContainsComponent] A non-renderable value${keys} is being passed as a React child. ` +\n \"React will throw 'Objects are not valid as a React child' at the real render site. \" +\n \"Stringify it (e.g. JSON.stringify) before rendering.\",\n node,\n );\n }\n return false;\n}\n"],"mappings":";AAiBA,YAAY,WAAW;AAEvB,IAAM,oBAAoB,uBAAO,IAAI,cAAc;AAkB5C,SAAS,sBACd,MACA,WACS;AACT,MAAI,QAAQ,QAAQ,OAAO,SAAS,UAAW,QAAO;AAEtD,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,KAAK,CAAC,UAAU,sBAAsB,OAAO,SAAS,CAAC;AAAA,EACrE;AAEA,MAAU,qBAAe,IAAI,GAAG;AAC9B,QAAI,KAAK,SAAS,UAAW,QAAO;AACpC,UAAM,QAAQ,KAAK;AACnB,WAAO,MAAM,YAAY,OACrB,sBAAsB,MAAM,UAAU,SAAS,IAC/C;AAAA,EACN;AAGA,MAAI,OAAO,SAAS,YAAY,OAAO,SAAS,SAAU,QAAO;AAGjE,MACE,OAAO,SAAS,YACf,KAAgC,aAAa,mBAC9C;AACA,WAAO;AAAA,MACJ,KAAwC;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAIA,MAAI,OAAO,SAAS,YAAY,OAAO,YAAY,MAAM;AACvD,WAAO,MAAM,KAAK,IAAiC,EAAE;AAAA,MAAK,CAAC,UACzD,sBAAsB,OAAO,SAAS;AAAA,IACxC;AAAA,EACF;AAIA,MACE,OAAO,YAAY,eACnB,MACA;AACA,UAAM,OACJ,OAAO,SAAS,WACZ,eAAe,OAAO,KAAK,IAAI,EAAE,KAAK,IAAI,CAAC,MAC3C;AACN,YAAQ;AAAA,MACN,iDAAiD,IAAI;AAAA,MAGrD;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/react-tree.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/react-tree — safe React children-tree scanning.\n *\n * Ported from matrx-frontend `lib/react/treeContainsComponent.ts`; this\n * subpath is the ONE home of the scanner inside the kit (the `/confirm`\n * subpath's alert-dialog imports it from here — no duplicate bodies).\n *\n * Two deliberate divergences from the frontend original, both documented:\n * - the dev-mode scream checks `typeof process` first, since this package may\n * load in an unbundled browser context where `process` is undefined;\n * - a React PORTAL child (`createPortal(...)` passed as a child) is a valid\n * React child, but it is not an element, an iterable, or a primitive — the\n * original fell through to the non-renderable branch, screamed a false\n * positive in dev, and skipped the portal's content. Portals are now\n * recognized and their children traversed.\n */\n\nimport * as React from \"react\";\n\nconst REACT_PORTAL_TYPE = Symbol.for(\"react.portal\");\n\n/**\n * Returns true if `Component` appears anywhere in the React element tree under\n * `node`. Used to detect optional a11y children (e.g. DialogDescription)\n * without rendering duplicates.\n *\n * DEFENSIVE + LOUD. A non-renderable node — a plain object or function passed\n * as a React child — is a real bug: React throws \"Objects are not valid as a\n * React child\" the instant it renders one. This a11y probe must NOT be the\n * crash site. `React.Children.toArray` would throw HERE, producing a trace that\n * points at the dialog primitive instead of the component that leaked the\n * object (this misdirection has burned real debugging hours). So we walk the\n * tree by hand, SKIP any non-renderable node, and scream in dev with its keys —\n * then let React report the defect at the true render site with the offending\n * component in the stack. For every VALID tree the result is identical to the\n * old `React.Children.toArray(node).some(...)`.\n */\nexport function treeContainsComponent(\n node: React.ReactNode,\n Component: React.ElementType,\n): boolean {\n if (node == null || typeof node === \"boolean\") return false;\n\n if (Array.isArray(node)) {\n return node.some((child) => treeContainsComponent(child, Component));\n }\n\n if (React.isValidElement(node)) {\n if (node.type === Component) return true;\n const props = node.props as { children?: React.ReactNode };\n return props.children != null\n ? treeContainsComponent(props.children, Component)\n : false;\n }\n\n // Strings / numbers are valid leaf children but never the Component.\n if (typeof node === \"string\" || typeof node === \"number\") return false;\n\n // A portal is a valid child that is NOT an element: traverse its content.\n if (\n typeof node === \"object\" &&\n (node as { $$typeof?: unknown }).$$typeof === REACT_PORTAL_TYPE\n ) {\n return treeContainsComponent(\n (node as { children?: React.ReactNode }).children,\n Component,\n );\n }\n\n // Non-array iterables (Set, Map, generator) are valid React children — React\n // supports them — so traverse rather than reject.\n if (typeof node === \"object\" && Symbol.iterator in node) {\n return Array.from(node as Iterable<React.ReactNode>).some((child) =>\n treeContainsComponent(child, Component),\n );\n }\n\n // Anything else (a raw object, a function) is NOT a valid React child. React\n // will throw when it renders this; we must not throw first and hide the cause.\n const runtimeProcess = (\n globalThis as { process?: { env?: { NODE_ENV?: string } } }\n ).process;\n if (runtimeProcess?.env?.NODE_ENV !== \"production\") {\n const keys =\n typeof node === \"object\"\n ? ` with keys {${Object.keys(node).join(\", \")}}`\n : \"\";\n console.error(\n `[treeContainsComponent] A non-renderable value${keys} is being passed as a React child. ` +\n \"React will throw 'Objects are not valid as a React child' at the real render site. \" +\n \"Stringify it (e.g. JSON.stringify) before rendering.\",\n node,\n );\n }\n return false;\n}\n"],"mappings":";AAiBA,YAAY,WAAW;AAEvB,IAAM,oBAAoB,uBAAO,IAAI,cAAc;AAkB5C,SAAS,sBACd,MACA,WACS;AACT,MAAI,QAAQ,QAAQ,OAAO,SAAS,UAAW,QAAO;AAEtD,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,KAAK,CAAC,UAAU,sBAAsB,OAAO,SAAS,CAAC;AAAA,EACrE;AAEA,MAAU,qBAAe,IAAI,GAAG;AAC9B,QAAI,KAAK,SAAS,UAAW,QAAO;AACpC,UAAM,QAAQ,KAAK;AACnB,WAAO,MAAM,YAAY,OACrB,sBAAsB,MAAM,UAAU,SAAS,IAC/C;AAAA,EACN;AAGA,MAAI,OAAO,SAAS,YAAY,OAAO,SAAS,SAAU,QAAO;AAGjE,MACE,OAAO,SAAS,YACf,KAAgC,aAAa,mBAC9C;AACA,WAAO;AAAA,MACJ,KAAwC;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAIA,MAAI,OAAO,SAAS,YAAY,OAAO,YAAY,MAAM;AACvD,WAAO,MAAM,KAAK,IAAiC,EAAE;AAAA,MAAK,CAAC,UACzD,sBAAsB,OAAO,SAAS;AAAA,IACxC;AAAA,EACF;AAIA,QAAM,iBACJ,WACA;AACF,MAAI,gBAAgB,KAAK,aAAa,cAAc;AAClD,UAAM,OACJ,OAAO,SAAS,WACZ,eAAe,OAAO,KAAK,IAAI,EAAE,KAAK,IAAI,CAAC,MAC3C;AACN,YAAQ;AAAA,MACN,iDAAiD,IAAI;AAAA,MAGrD;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/short-link.ts
21
+ var short_link_exports = {};
22
+ __export(short_link_exports, {
23
+ SHORT_LINK_PATH_PREFIX: () => SHORT_LINK_PATH_PREFIX,
24
+ SHORT_LINK_TOKEN_ALPHABET: () => SHORT_LINK_TOKEN_ALPHABET,
25
+ SHORT_LINK_TOKEN_LENGTH: () => SHORT_LINK_TOKEN_LENGTH,
26
+ isShortLinkToken: () => isShortLinkToken,
27
+ normalizeShortLinkToken: () => normalizeShortLinkToken,
28
+ shortLinkPath: () => shortLinkPath,
29
+ shortLinkUrl: () => shortLinkUrl
30
+ });
31
+ module.exports = __toCommonJS(short_link_exports);
32
+ var SHORT_LINK_TOKEN_ALPHABET = "23456789abcdefghijkmnpqrstuvwxyz";
33
+ var SHORT_LINK_TOKEN_LENGTH = 10;
34
+ var SHORT_LINK_PATH_PREFIX = "/r/";
35
+ var TOKEN_RE = new RegExp(`^[${SHORT_LINK_TOKEN_ALPHABET}]{${SHORT_LINK_TOKEN_LENGTH}}$`);
36
+ function normalizeShortLinkToken(candidate) {
37
+ const token = (candidate ?? "").trim().toLowerCase();
38
+ return TOKEN_RE.test(token) ? token : null;
39
+ }
40
+ function isShortLinkToken(candidate) {
41
+ return normalizeShortLinkToken(candidate) !== null;
42
+ }
43
+ function shortLinkPath(token) {
44
+ const normalized = normalizeShortLinkToken(token);
45
+ if (!normalized) {
46
+ throw new Error(
47
+ `shortLinkPath: ${JSON.stringify(token)} is not a short-link token (${SHORT_LINK_TOKEN_LENGTH} chars of "${SHORT_LINK_TOKEN_ALPHABET}")`
48
+ );
49
+ }
50
+ return `${SHORT_LINK_PATH_PREFIX}${normalized}`;
51
+ }
52
+ function shortLinkUrl(origin, token) {
53
+ return `${origin.replace(/\/+$/, "")}${shortLinkPath(token)}`;
54
+ }
55
+ //# sourceMappingURL=short-link.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/short-link.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/short-link — the platform short-link CONTRACT, in one place.\n *\n * The primitive itself lives in the database (migration `0557_platform_short_links`):\n * `platform.short_links` holds `token → same-app path`, org-scoped and expiring;\n * `platform.create_short_link` mints (server-side only); `public.resolve_short_link`\n * resolves (anon-callable; answers with a PATH, never content — the target route's\n * own auth gates everything). The frontend redirect route is `/r/[token]`\n * (matrx-frontend `app/(public)/r/[token]`), and the notification spine mints per\n * SMS leg (aidream `services/notifications/short_links.py`).\n *\n * This module is the shared vocabulary every client needs to speak about those\n * tokens — alphabet, length, validation, and the URL shape — so no consumer ever\n * re-declares it. 🚨 `SHORT_LINK_TOKEN_ALPHABET` and `SHORT_LINK_TOKEN_LENGTH`\n * mirror `platform.create_short_link` EXACTLY; change one and you change both.\n *\n * 🚨 A short link is a URL, not a permission. The primitive that grants\n * anonymous access to content is `platform.share_links` (`/s/[token]`, 64-hex\n * tokens) — a different system, deliberately. Never shorten by minting a share\n * link, and never share by minting a short link.\n *\n * Pure logic — no DOM, no React, no network; safe in Server Components, route\n * handlers, workers, and Node scripts.\n */\n\n/**\n * 32 characters: digits 2–9 plus a–z minus `l` and `o`. 256 % 32 = 0, so the\n * mint maps random bytes without modulo bias; lowercase-only survives channels\n * that case-mangle (the resolver lowercases before lookup); the ambiguous\n * glyphs (`0/o`, `1/l`) never appear.\n */\nexport const SHORT_LINK_TOKEN_ALPHABET = \"23456789abcdefghijkmnpqrstuvwxyz\";\n\n/** 10 characters × 5 bits = 50 bits — unguessable at any realistic probe rate. */\nexport const SHORT_LINK_TOKEN_LENGTH = 10;\n\n/** The resolve route on the app origin (matrx-frontend `app/(public)/r/[token]`). */\nexport const SHORT_LINK_PATH_PREFIX = \"/r/\";\n\nconst TOKEN_RE = new RegExp(`^[${SHORT_LINK_TOKEN_ALPHABET}]{${SHORT_LINK_TOKEN_LENGTH}}$`);\n\n/**\n * Trim, lowercase, and shape-check a candidate token. Returns the normalized\n * token, or `null` for anything outside the contract — the resolver would\n * refuse it anyway, so callers can skip the round trip.\n */\nexport function normalizeShortLinkToken(candidate: string | null | undefined): string | null {\n const token = (candidate ?? \"\").trim().toLowerCase();\n return TOKEN_RE.test(token) ? token : null;\n}\n\n/** Whether a string is a well-formed short-link token (after normalization). */\nexport function isShortLinkToken(candidate: string | null | undefined): boolean {\n return normalizeShortLinkToken(candidate) !== null;\n}\n\n/** The app-relative path a token resolves at: `/r/<token>`. */\nexport function shortLinkPath(token: string): string {\n const normalized = normalizeShortLinkToken(token);\n if (!normalized) {\n throw new Error(\n `shortLinkPath: ${JSON.stringify(token)} is not a short-link token ` +\n `(${SHORT_LINK_TOKEN_LENGTH} chars of \"${SHORT_LINK_TOKEN_ALPHABET}\")`,\n );\n }\n return `${SHORT_LINK_PATH_PREFIX}${normalized}`;\n}\n\n/**\n * The absolute short URL for a token on a given origin, e.g.\n * `shortLinkUrl(\"https://app.aimatrx.com\", token)` → `https://app.aimatrx.com/r/<token>`.\n */\nexport function shortLinkUrl(origin: string, token: string): string {\n return `${origin.replace(/\\/+$/, \"\")}${shortLinkPath(token)}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BO,IAAM,4BAA4B;AAGlC,IAAM,0BAA0B;AAGhC,IAAM,yBAAyB;AAEtC,IAAM,WAAW,IAAI,OAAO,KAAK,yBAAyB,KAAK,uBAAuB,IAAI;AAOnF,SAAS,wBAAwB,WAAqD;AAC3F,QAAM,SAAS,aAAa,IAAI,KAAK,EAAE,YAAY;AACnD,SAAO,SAAS,KAAK,KAAK,IAAI,QAAQ;AACxC;AAGO,SAAS,iBAAiB,WAA+C;AAC9E,SAAO,wBAAwB,SAAS,MAAM;AAChD;AAGO,SAAS,cAAc,OAAuB;AACnD,QAAM,aAAa,wBAAwB,KAAK;AAChD,MAAI,CAAC,YAAY;AACf,UAAM,IAAI;AAAA,MACR,kBAAkB,KAAK,UAAU,KAAK,CAAC,+BACjC,uBAAuB,cAAc,yBAAyB;AAAA,IACtE;AAAA,EACF;AACA,SAAO,GAAG,sBAAsB,GAAG,UAAU;AAC/C;AAMO,SAAS,aAAa,QAAgB,OAAuB;AAClE,SAAO,GAAG,OAAO,QAAQ,QAAQ,EAAE,CAAC,GAAG,cAAc,KAAK,CAAC;AAC7D;","names":[]}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @ai-matrx/kit/short-link — the platform short-link CONTRACT, in one place.
3
+ *
4
+ * The primitive itself lives in the database (migration `0557_platform_short_links`):
5
+ * `platform.short_links` holds `token → same-app path`, org-scoped and expiring;
6
+ * `platform.create_short_link` mints (server-side only); `public.resolve_short_link`
7
+ * resolves (anon-callable; answers with a PATH, never content — the target route's
8
+ * own auth gates everything). The frontend redirect route is `/r/[token]`
9
+ * (matrx-frontend `app/(public)/r/[token]`), and the notification spine mints per
10
+ * SMS leg (aidream `services/notifications/short_links.py`).
11
+ *
12
+ * This module is the shared vocabulary every client needs to speak about those
13
+ * tokens — alphabet, length, validation, and the URL shape — so no consumer ever
14
+ * re-declares it. 🚨 `SHORT_LINK_TOKEN_ALPHABET` and `SHORT_LINK_TOKEN_LENGTH`
15
+ * mirror `platform.create_short_link` EXACTLY; change one and you change both.
16
+ *
17
+ * 🚨 A short link is a URL, not a permission. The primitive that grants
18
+ * anonymous access to content is `platform.share_links` (`/s/[token]`, 64-hex
19
+ * tokens) — a different system, deliberately. Never shorten by minting a share
20
+ * link, and never share by minting a short link.
21
+ *
22
+ * Pure logic — no DOM, no React, no network; safe in Server Components, route
23
+ * handlers, workers, and Node scripts.
24
+ */
25
+ /**
26
+ * 32 characters: digits 2–9 plus a–z minus `l` and `o`. 256 % 32 = 0, so the
27
+ * mint maps random bytes without modulo bias; lowercase-only survives channels
28
+ * that case-mangle (the resolver lowercases before lookup); the ambiguous
29
+ * glyphs (`0/o`, `1/l`) never appear.
30
+ */
31
+ declare const SHORT_LINK_TOKEN_ALPHABET = "23456789abcdefghijkmnpqrstuvwxyz";
32
+ /** 10 characters × 5 bits = 50 bits — unguessable at any realistic probe rate. */
33
+ declare const SHORT_LINK_TOKEN_LENGTH = 10;
34
+ /** The resolve route on the app origin (matrx-frontend `app/(public)/r/[token]`). */
35
+ declare const SHORT_LINK_PATH_PREFIX = "/r/";
36
+ /**
37
+ * Trim, lowercase, and shape-check a candidate token. Returns the normalized
38
+ * token, or `null` for anything outside the contract — the resolver would
39
+ * refuse it anyway, so callers can skip the round trip.
40
+ */
41
+ declare function normalizeShortLinkToken(candidate: string | null | undefined): string | null;
42
+ /** Whether a string is a well-formed short-link token (after normalization). */
43
+ declare function isShortLinkToken(candidate: string | null | undefined): boolean;
44
+ /** The app-relative path a token resolves at: `/r/<token>`. */
45
+ declare function shortLinkPath(token: string): string;
46
+ /**
47
+ * The absolute short URL for a token on a given origin, e.g.
48
+ * `shortLinkUrl("https://app.aimatrx.com", token)` → `https://app.aimatrx.com/r/<token>`.
49
+ */
50
+ declare function shortLinkUrl(origin: string, token: string): string;
51
+
52
+ export { SHORT_LINK_PATH_PREFIX, SHORT_LINK_TOKEN_ALPHABET, SHORT_LINK_TOKEN_LENGTH, isShortLinkToken, normalizeShortLinkToken, shortLinkPath, shortLinkUrl };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @ai-matrx/kit/short-link — the platform short-link CONTRACT, in one place.
3
+ *
4
+ * The primitive itself lives in the database (migration `0557_platform_short_links`):
5
+ * `platform.short_links` holds `token → same-app path`, org-scoped and expiring;
6
+ * `platform.create_short_link` mints (server-side only); `public.resolve_short_link`
7
+ * resolves (anon-callable; answers with a PATH, never content — the target route's
8
+ * own auth gates everything). The frontend redirect route is `/r/[token]`
9
+ * (matrx-frontend `app/(public)/r/[token]`), and the notification spine mints per
10
+ * SMS leg (aidream `services/notifications/short_links.py`).
11
+ *
12
+ * This module is the shared vocabulary every client needs to speak about those
13
+ * tokens — alphabet, length, validation, and the URL shape — so no consumer ever
14
+ * re-declares it. 🚨 `SHORT_LINK_TOKEN_ALPHABET` and `SHORT_LINK_TOKEN_LENGTH`
15
+ * mirror `platform.create_short_link` EXACTLY; change one and you change both.
16
+ *
17
+ * 🚨 A short link is a URL, not a permission. The primitive that grants
18
+ * anonymous access to content is `platform.share_links` (`/s/[token]`, 64-hex
19
+ * tokens) — a different system, deliberately. Never shorten by minting a share
20
+ * link, and never share by minting a short link.
21
+ *
22
+ * Pure logic — no DOM, no React, no network; safe in Server Components, route
23
+ * handlers, workers, and Node scripts.
24
+ */
25
+ /**
26
+ * 32 characters: digits 2–9 plus a–z minus `l` and `o`. 256 % 32 = 0, so the
27
+ * mint maps random bytes without modulo bias; lowercase-only survives channels
28
+ * that case-mangle (the resolver lowercases before lookup); the ambiguous
29
+ * glyphs (`0/o`, `1/l`) never appear.
30
+ */
31
+ declare const SHORT_LINK_TOKEN_ALPHABET = "23456789abcdefghijkmnpqrstuvwxyz";
32
+ /** 10 characters × 5 bits = 50 bits — unguessable at any realistic probe rate. */
33
+ declare const SHORT_LINK_TOKEN_LENGTH = 10;
34
+ /** The resolve route on the app origin (matrx-frontend `app/(public)/r/[token]`). */
35
+ declare const SHORT_LINK_PATH_PREFIX = "/r/";
36
+ /**
37
+ * Trim, lowercase, and shape-check a candidate token. Returns the normalized
38
+ * token, or `null` for anything outside the contract — the resolver would
39
+ * refuse it anyway, so callers can skip the round trip.
40
+ */
41
+ declare function normalizeShortLinkToken(candidate: string | null | undefined): string | null;
42
+ /** Whether a string is a well-formed short-link token (after normalization). */
43
+ declare function isShortLinkToken(candidate: string | null | undefined): boolean;
44
+ /** The app-relative path a token resolves at: `/r/<token>`. */
45
+ declare function shortLinkPath(token: string): string;
46
+ /**
47
+ * The absolute short URL for a token on a given origin, e.g.
48
+ * `shortLinkUrl("https://app.aimatrx.com", token)` → `https://app.aimatrx.com/r/<token>`.
49
+ */
50
+ declare function shortLinkUrl(origin: string, token: string): string;
51
+
52
+ export { SHORT_LINK_PATH_PREFIX, SHORT_LINK_TOKEN_ALPHABET, SHORT_LINK_TOKEN_LENGTH, isShortLinkToken, normalizeShortLinkToken, shortLinkPath, shortLinkUrl };
@@ -0,0 +1,34 @@
1
+ // src/short-link.ts
2
+ var SHORT_LINK_TOKEN_ALPHABET = "23456789abcdefghijkmnpqrstuvwxyz";
3
+ var SHORT_LINK_TOKEN_LENGTH = 10;
4
+ var SHORT_LINK_PATH_PREFIX = "/r/";
5
+ var TOKEN_RE = new RegExp(`^[${SHORT_LINK_TOKEN_ALPHABET}]{${SHORT_LINK_TOKEN_LENGTH}}$`);
6
+ function normalizeShortLinkToken(candidate) {
7
+ const token = (candidate ?? "").trim().toLowerCase();
8
+ return TOKEN_RE.test(token) ? token : null;
9
+ }
10
+ function isShortLinkToken(candidate) {
11
+ return normalizeShortLinkToken(candidate) !== null;
12
+ }
13
+ function shortLinkPath(token) {
14
+ const normalized = normalizeShortLinkToken(token);
15
+ if (!normalized) {
16
+ throw new Error(
17
+ `shortLinkPath: ${JSON.stringify(token)} is not a short-link token (${SHORT_LINK_TOKEN_LENGTH} chars of "${SHORT_LINK_TOKEN_ALPHABET}")`
18
+ );
19
+ }
20
+ return `${SHORT_LINK_PATH_PREFIX}${normalized}`;
21
+ }
22
+ function shortLinkUrl(origin, token) {
23
+ return `${origin.replace(/\/+$/, "")}${shortLinkPath(token)}`;
24
+ }
25
+ export {
26
+ SHORT_LINK_PATH_PREFIX,
27
+ SHORT_LINK_TOKEN_ALPHABET,
28
+ SHORT_LINK_TOKEN_LENGTH,
29
+ isShortLinkToken,
30
+ normalizeShortLinkToken,
31
+ shortLinkPath,
32
+ shortLinkUrl
33
+ };
34
+ //# sourceMappingURL=short-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/short-link.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/short-link — the platform short-link CONTRACT, in one place.\n *\n * The primitive itself lives in the database (migration `0557_platform_short_links`):\n * `platform.short_links` holds `token → same-app path`, org-scoped and expiring;\n * `platform.create_short_link` mints (server-side only); `public.resolve_short_link`\n * resolves (anon-callable; answers with a PATH, never content — the target route's\n * own auth gates everything). The frontend redirect route is `/r/[token]`\n * (matrx-frontend `app/(public)/r/[token]`), and the notification spine mints per\n * SMS leg (aidream `services/notifications/short_links.py`).\n *\n * This module is the shared vocabulary every client needs to speak about those\n * tokens — alphabet, length, validation, and the URL shape — so no consumer ever\n * re-declares it. 🚨 `SHORT_LINK_TOKEN_ALPHABET` and `SHORT_LINK_TOKEN_LENGTH`\n * mirror `platform.create_short_link` EXACTLY; change one and you change both.\n *\n * 🚨 A short link is a URL, not a permission. The primitive that grants\n * anonymous access to content is `platform.share_links` (`/s/[token]`, 64-hex\n * tokens) — a different system, deliberately. Never shorten by minting a share\n * link, and never share by minting a short link.\n *\n * Pure logic — no DOM, no React, no network; safe in Server Components, route\n * handlers, workers, and Node scripts.\n */\n\n/**\n * 32 characters: digits 2–9 plus a–z minus `l` and `o`. 256 % 32 = 0, so the\n * mint maps random bytes without modulo bias; lowercase-only survives channels\n * that case-mangle (the resolver lowercases before lookup); the ambiguous\n * glyphs (`0/o`, `1/l`) never appear.\n */\nexport const SHORT_LINK_TOKEN_ALPHABET = \"23456789abcdefghijkmnpqrstuvwxyz\";\n\n/** 10 characters × 5 bits = 50 bits — unguessable at any realistic probe rate. */\nexport const SHORT_LINK_TOKEN_LENGTH = 10;\n\n/** The resolve route on the app origin (matrx-frontend `app/(public)/r/[token]`). */\nexport const SHORT_LINK_PATH_PREFIX = \"/r/\";\n\nconst TOKEN_RE = new RegExp(`^[${SHORT_LINK_TOKEN_ALPHABET}]{${SHORT_LINK_TOKEN_LENGTH}}$`);\n\n/**\n * Trim, lowercase, and shape-check a candidate token. Returns the normalized\n * token, or `null` for anything outside the contract — the resolver would\n * refuse it anyway, so callers can skip the round trip.\n */\nexport function normalizeShortLinkToken(candidate: string | null | undefined): string | null {\n const token = (candidate ?? \"\").trim().toLowerCase();\n return TOKEN_RE.test(token) ? token : null;\n}\n\n/** Whether a string is a well-formed short-link token (after normalization). */\nexport function isShortLinkToken(candidate: string | null | undefined): boolean {\n return normalizeShortLinkToken(candidate) !== null;\n}\n\n/** The app-relative path a token resolves at: `/r/<token>`. */\nexport function shortLinkPath(token: string): string {\n const normalized = normalizeShortLinkToken(token);\n if (!normalized) {\n throw new Error(\n `shortLinkPath: ${JSON.stringify(token)} is not a short-link token ` +\n `(${SHORT_LINK_TOKEN_LENGTH} chars of \"${SHORT_LINK_TOKEN_ALPHABET}\")`,\n );\n }\n return `${SHORT_LINK_PATH_PREFIX}${normalized}`;\n}\n\n/**\n * The absolute short URL for a token on a given origin, e.g.\n * `shortLinkUrl(\"https://app.aimatrx.com\", token)` → `https://app.aimatrx.com/r/<token>`.\n */\nexport function shortLinkUrl(origin: string, token: string): string {\n return `${origin.replace(/\\/+$/, \"\")}${shortLinkPath(token)}`;\n}\n"],"mappings":";AA+BO,IAAM,4BAA4B;AAGlC,IAAM,0BAA0B;AAGhC,IAAM,yBAAyB;AAEtC,IAAM,WAAW,IAAI,OAAO,KAAK,yBAAyB,KAAK,uBAAuB,IAAI;AAOnF,SAAS,wBAAwB,WAAqD;AAC3F,QAAM,SAAS,aAAa,IAAI,KAAK,EAAE,YAAY;AACnD,SAAO,SAAS,KAAK,KAAK,IAAI,QAAQ;AACxC;AAGO,SAAS,iBAAiB,WAA+C;AAC9E,SAAO,wBAAwB,SAAS,MAAM;AAChD;AAGO,SAAS,cAAc,OAAuB;AACnD,QAAM,aAAa,wBAAwB,KAAK;AAChD,MAAI,CAAC,YAAY;AACf,UAAM,IAAI;AAAA,MACR,kBAAkB,KAAK,UAAU,KAAK,CAAC,+BACjC,uBAAuB,cAAc,yBAAyB;AAAA,IACtE;AAAA,EACF;AACA,SAAO,GAAG,sBAAsB,GAAG,UAAU;AAC/C;AAMO,SAAS,aAAa,QAAgB,OAAuB;AAClE,SAAO,GAAG,OAAO,QAAQ,QAAQ,EAAE,CAAC,GAAG,cAAc,KAAK,CAAC;AAC7D;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-matrx/kit",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "The always-include AI Matrx kit: the little primitives every Matrx app speaks — autosave that never loses a keystroke, stale-response guards, clipboard with graceful fallbacks — one per subpath, tree-shaken to what you use.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -21,7 +21,8 @@
21
21
  "markdown-streaming",
22
22
  "indexeddb",
23
23
  "tailwind-colors",
24
- "qr-code"
24
+ "qr-code",
25
+ "short-link"
25
26
  ],
26
27
  "repository": {
27
28
  "type": "git",
@@ -239,6 +240,16 @@
239
240
  "types": "./dist/qr.d.cts",
240
241
  "default": "./dist/qr.cjs"
241
242
  }
243
+ },
244
+ "./short-link": {
245
+ "import": {
246
+ "types": "./dist/short-link.d.ts",
247
+ "default": "./dist/short-link.js"
248
+ },
249
+ "require": {
250
+ "types": "./dist/short-link.d.cts",
251
+ "default": "./dist/short-link.cjs"
252
+ }
242
253
  }
243
254
  },
244
255
  "dependencies": {