@aglyn/plugins-forms 1.0.0-beta.143

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 (45) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +35 -0
  3. package/package.json +52 -0
  4. package/src/index.d.ts +18 -0
  5. package/src/index.js +19 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/form-design-preview.component.d.ts +68 -0
  8. package/src/lib/components/form-design-preview.component.js +238 -0
  9. package/src/lib/components/form-design-preview.component.js.map +1 -0
  10. package/src/lib/components/form-detail-card.d.ts +53 -0
  11. package/src/lib/components/form-detail-card.js +827 -0
  12. package/src/lib/components/form-detail-card.js.map +1 -0
  13. package/src/lib/components/form-metrics-card.component.d.ts +67 -0
  14. package/src/lib/components/form-metrics-card.component.js +298 -0
  15. package/src/lib/components/form-metrics-card.component.js.map +1 -0
  16. package/src/lib/components/form-submissions-card.component.d.ts +40 -0
  17. package/src/lib/components/form-submissions-card.component.js +104 -0
  18. package/src/lib/components/form-submissions-card.component.js.map +1 -0
  19. package/src/lib/components/form-zones.d.ts +52 -0
  20. package/src/lib/components/form-zones.js +20 -0
  21. package/src/lib/components/form-zones.js.map +1 -0
  22. package/src/lib/components/form.d.ts +186 -0
  23. package/src/lib/components/form.js +1014 -0
  24. package/src/lib/components/form.js.map +1 -0
  25. package/src/lib/components/forms-console-page.d.ts +22 -0
  26. package/src/lib/components/forms-console-page.js +55 -0
  27. package/src/lib/components/forms-console-page.js.map +1 -0
  28. package/src/lib/components/host-forms-card.component.d.ts +56 -0
  29. package/src/lib/components/host-forms-card.component.js +533 -0
  30. package/src/lib/components/host-forms-card.component.js.map +1 -0
  31. package/src/lib/components/use-form-promote-api.d.ts +48 -0
  32. package/src/lib/components/use-form-promote-api.js +63 -0
  33. package/src/lib/components/use-form-promote-api.js.map +1 -0
  34. package/src/lib/constants/bundle-common.d.ts +31 -0
  35. package/src/lib/constants/bundle-common.js +31 -0
  36. package/src/lib/constants/bundle-common.js.map +1 -0
  37. package/src/lib/plugin.d.ts +25 -0
  38. package/src/lib/plugin.js +76 -0
  39. package/src/lib/plugin.js.map +1 -0
  40. package/src/lib/site.d.ts +53 -0
  41. package/src/lib/site.js +83 -0
  42. package/src/lib/site.js.map +1 -0
  43. package/src/lib/utils/generate-preset-id.d.ts +25 -0
  44. package/src/lib/utils/generate-preset-id.js +30 -0
  45. package/src/lib/utils/generate-preset-id.js.map +1 -0
@@ -0,0 +1,48 @@
1
+ import type { FormContractViolation } from '@aglyn/aglyn';
2
+ /**
3
+ * What the route refused with, or what it did.
4
+ *
5
+ * ONE shape rather than a discriminated union: `strictNullChecks` is off in
6
+ * this repo, so narrowing on an `ok: true | false` discriminant does not
7
+ * happen and every read of `message` would need a cast. A caller reads
8
+ * `message` and `violations` only after seeing `ok === false`, and both are
9
+ * always populated on a refusal — `violations` as an empty array when the
10
+ * refusal was not about the contract at all (a role denial, a lockdown, a
11
+ * version with no design).
12
+ */
13
+ export interface PromoteFormResult {
14
+ ok: boolean;
15
+ /**
16
+ * Author-facing, and stated by the ROUTE. Present on a refusal.
17
+ */
18
+ message?: string;
19
+ /**
20
+ * The contract violations, verbatim.
21
+ *
22
+ * The codes and sentences are `checkFormContract`'s own, so the page renders
23
+ * exactly what the besigner renders and neither side parses prose.
24
+ */
25
+ violations?: FormContractViolation[];
26
+ }
27
+ /** Promote one version of one form, by id — no design crosses the wire. */
28
+ export type PromoteForm = (options: {
29
+ hostId: string;
30
+ formId: string;
31
+ versionId: string;
32
+ }) => Promise<PromoteFormResult>;
33
+ /**
34
+ * Makes one version of a form the version the site serves.
35
+ *
36
+ * Server-side, and never a client `updateDoc`, because promotion is where the
37
+ * form's contract is enforced: `/api/hosts/forms/promote` re-reads the stored
38
+ * version, runs `checkFormContract` on the tree it is about to write, and
39
+ * refuses with a 422 rather than publishing a design whose submissions would
40
+ * silently stop arriving. A console-side check is advice; that route is the
41
+ * enforcement, so this hook sends three ids and no design at all.
42
+ *
43
+ * Resolves rather than throws on a refusal: a broken contract is an ordinary
44
+ * outcome an author is expected to see and fix, and the violations are the
45
+ * payload, not an error message.
46
+ */
47
+ export declare function useFormPromoteApi(): PromoteForm;
48
+ export default useFormPromoteApi;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { useUser } from "@aglyn/tenant-feature-instance";
18
+ import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
19
+ import { useCallback } from "react";
20
+ /**
21
+ * Makes one version of a form the version the site serves.
22
+ *
23
+ * Server-side, and never a client `updateDoc`, because promotion is where the
24
+ * form's contract is enforced: `/api/hosts/forms/promote` re-reads the stored
25
+ * version, runs `checkFormContract` on the tree it is about to write, and
26
+ * refuses with a 422 rather than publishing a design whose submissions would
27
+ * silently stop arriving. A console-side check is advice; that route is the
28
+ * enforcement, so this hook sends three ids and no design at all.
29
+ *
30
+ * Resolves rather than throws on a refusal: a broken contract is an ordinary
31
+ * outcome an author is expected to see and fix, and the violations are the
32
+ * payload, not an error message.
33
+ */ export function useFormPromoteApi() {
34
+ const { data: user } = useUser();
35
+ return useCallback(async ({ hostId, formId, versionId })=>{
36
+ var _ref;
37
+ const response = await authorizedFetch(user, '/api/hosts/forms/promote', {
38
+ method: 'POST',
39
+ headers: {
40
+ 'Content-Type': 'application/json'
41
+ },
42
+ body: JSON.stringify({
43
+ hostId,
44
+ formId,
45
+ versionId
46
+ })
47
+ });
48
+ const payload = await response.json().catch(()=>({}));
49
+ if (response.ok) return {
50
+ ok: true
51
+ };
52
+ return {
53
+ ok: false,
54
+ message: String((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'Publish failed'),
55
+ violations: Array.isArray(payload == null ? void 0 : payload.violations) ? payload.violations : []
56
+ };
57
+ }, [
58
+ user
59
+ ]);
60
+ }
61
+ export default useFormPromoteApi;
62
+
63
+ //# sourceMappingURL=use-form-promote-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/forms/src/lib/components/use-form-promote-api.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport type { FormContractViolation } from '@aglyn/aglyn'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useCallback } from 'react'\n\n/**\n * What the route refused with, or what it did.\n *\n * ONE shape rather than a discriminated union: `strictNullChecks` is off in\n * this repo, so narrowing on an `ok: true | false` discriminant does not\n * happen and every read of `message` would need a cast. A caller reads\n * `message` and `violations` only after seeing `ok === false`, and both are\n * always populated on a refusal — `violations` as an empty array when the\n * refusal was not about the contract at all (a role denial, a lockdown, a\n * version with no design).\n */\nexport interface PromoteFormResult {\n ok: boolean\n /**\n * Author-facing, and stated by the ROUTE. Present on a refusal.\n */\n message?: string\n /**\n * The contract violations, verbatim.\n *\n * The codes and sentences are `checkFormContract`'s own, so the page renders\n * exactly what the besigner renders and neither side parses prose.\n */\n violations?: FormContractViolation[]\n}\n\n/** Promote one version of one form, by id — no design crosses the wire. */\nexport type PromoteForm = (options: {\n hostId: string\n formId: string\n versionId: string\n}) => Promise<PromoteFormResult>\n\n/**\n * Makes one version of a form the version the site serves.\n *\n * Server-side, and never a client `updateDoc`, because promotion is where the\n * form's contract is enforced: `/api/hosts/forms/promote` re-reads the stored\n * version, runs `checkFormContract` on the tree it is about to write, and\n * refuses with a 422 rather than publishing a design whose submissions would\n * silently stop arriving. A console-side check is advice; that route is the\n * enforcement, so this hook sends three ids and no design at all.\n *\n * Resolves rather than throws on a refusal: a broken contract is an ordinary\n * outcome an author is expected to see and fix, and the violations are the\n * payload, not an error message.\n */\nexport function useFormPromoteApi(): PromoteForm {\n const { data: user } = useUser()\n return useCallback<PromoteForm>(\n async ({ hostId, formId, versionId }) => {\n const response = await authorizedFetch(user, '/api/hosts/forms/promote', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ hostId, formId, versionId }),\n })\n const payload = await response.json().catch(() => ({}))\n if (response.ok) return { ok: true }\n return {\n ok: false,\n message: String(payload?.error ?? 'Publish failed'),\n violations: Array.isArray(payload?.violations)\n ? (payload.violations as FormContractViolation[])\n : [],\n }\n },\n [user],\n )\n}\n\nexport default useFormPromoteApi\n"],"names":["useUser","authorizedFetch","useCallback","useFormPromoteApi","data","user","hostId","formId","versionId","response","method","headers","body","JSON","stringify","payload","json","catch","ok","message","String","error","violations","Array","isArray"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAGA,SAASA,OAAO,QAAQ,iCAAgC;AACxD,SAASC,eAAe,QAAQ,2CAA0C;AAC1E,SAASC,WAAW,QAAQ,QAAO;AAmCnC;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC;IACd,MAAM,EAAEC,MAAMC,IAAI,EAAE,GAAGL;IACvB,OAAOE,YACL,OAAO,EAAEI,MAAM,EAAEC,MAAM,EAAEC,SAAS,EAAE;;QAClC,MAAMC,WAAW,MAAMR,gBAAgBI,MAAM,4BAA4B;YACvEK,QAAQ;YACRC,SAAS;gBAAE,gBAAgB;YAAmB;YAC9CC,MAAMC,KAAKC,SAAS,CAAC;gBAAER;gBAAQC;gBAAQC;YAAU;QACnD;QACA,MAAMO,UAAU,MAAMN,SAASO,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;QACpD,IAAIR,SAASS,EAAE,EAAE,OAAO;YAAEA,IAAI;QAAK;QACnC,OAAO;YACLA,IAAI;YACJC,SAASC,eAAOL,2BAAAA,QAASM,KAAK,mBAAI;YAClCC,YAAYC,MAAMC,OAAO,CAACT,2BAAAA,QAASO,UAAU,IACxCP,QAAQO,UAAU,GACnB,EAAE;QACR;IACF,GACA;QAACjB;KAAK;AAEV;AAEA,eAAeF,kBAAiB"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * The bundle id, persisted as `pluginId` on every node this bundle places.
19
+ *
20
+ * It is not a label. `requiredSitePlugins` reads `pluginId` off each saved
21
+ * node to decide which bundles must register before first paint, so this
22
+ * string is the answer to "which chunk does this page need in front of the
23
+ * render". A node whose `pluginId` names a bundle that no longer registers
24
+ * its `componentId` still RESOLVES — resolution is by component id alone —
25
+ * but it resolves a beat late, after the post-hydration load of the rest of
26
+ * the enabled set.
27
+ *
28
+ * `tools/scripts/backfill-node-plugin-ids.mjs` is what keeps the two in
29
+ * agreement across a bundle move.
30
+ */
31
+ export declare const BUNDLE_ID = "forms";
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ /**
17
+ * The bundle id, persisted as `pluginId` on every node this bundle places.
18
+ *
19
+ * It is not a label. `requiredSitePlugins` reads `pluginId` off each saved
20
+ * node to decide which bundles must register before first paint, so this
21
+ * string is the answer to "which chunk does this page need in front of the
22
+ * render". A node whose `pluginId` names a bundle that no longer registers
23
+ * its `componentId` still RESOLVES — resolution is by component id alone —
24
+ * but it resolves a beat late, after the post-hydration load of the rest of
25
+ * the enabled set.
26
+ *
27
+ * `tools/scripts/backfill-node-plugin-ids.mjs` is what keeps the two in
28
+ * agreement across a bundle move.
29
+ */ export const BUNDLE_ID = 'forms';
30
+
31
+ //# sourceMappingURL=bundle-common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/forms/src/lib/constants/bundle-common.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The bundle id, persisted as `pluginId` on every node this bundle places.\n *\n * It is not a label. `requiredSitePlugins` reads `pluginId` off each saved\n * node to decide which bundles must register before first paint, so this\n * string is the answer to \"which chunk does this page need in front of the\n * render\". A node whose `pluginId` names a bundle that no longer registers\n * its `componentId` still RESOLVES — resolution is by component id alone —\n * but it resolves a beat late, after the post-hydration load of the rest of\n * the enabled set.\n *\n * `tools/scripts/backfill-node-plugin-ids.mjs` is what keeps the two in\n * agreement across a bundle move.\n */\nexport const BUNDLE_ID = 'forms'\n"],"names":["BUNDLE_ID"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;CAaC,GACD,OAAO,MAAMA,YAAY,QAAO"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Console half: the Forms catalog and one form's own surface, served by the
19
+ * shell's generic plugin route.
20
+ *
21
+ * `ownsSubtree` because a form's detail URL names a document id rather than a
22
+ * declared section. Safe to call at console app load — the page is lazy.
23
+ */
24
+ export declare function registerFormsConsole(): void;
25
+ export * from './site';
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import * as Aglyn from "@aglyn/aglyn";
17
+ import { mdiEmailFastOutline } from "@aglyn/shared-data-mdi";
18
+ import { lazy } from "react";
19
+ import { registerPluginZone } from "@aglyn/aglyn/plugin-manager/plugin-zones";
20
+ import { FORM_CONTACT_FIELDS_ZONE, FORM_SUBMISSIONS_ZONE } from "./components/form-zones.js";
21
+ import { BUNDLE_ID } from "./constants/bundle-common.js";
22
+ /** Code-split: the Forms console surface only loads when opened. */ const FormsConsolePage = lazy(()=>import("./components/forms-console-page.js"));
23
+ /**
24
+ * Console half: the Forms catalog and one form's own surface, served by the
25
+ * shell's generic plugin route.
26
+ *
27
+ * `ownsSubtree` because a form's detail URL names a document id rather than a
28
+ * declared section. Safe to call at console app load — the page is lazy.
29
+ */ export function registerFormsConsole() {
30
+ registerPluginZone({
31
+ zone: FORM_SUBMISSIONS_ZONE,
32
+ label: 'One form’s submissions',
33
+ surface: 'console',
34
+ description: 'On one form’s page, behind the reader’s ask. A widget here reads the submissions to that form alone; it is handed the site and the form and nothing else.'
35
+ }, // Named, because a spec calls this registrar without the loader.
36
+ {
37
+ pluginId: BUNDLE_ID
38
+ });
39
+ registerPluginZone({
40
+ zone: FORM_CONTACT_FIELDS_ZONE,
41
+ label: 'Where a form’s fields save on the person',
42
+ surface: 'console',
43
+ description: 'On one form’s page, beside routing and consent. A widget here decides which of the person’s fields each form field saves to and hands the new declaration to `saveFields`; the page writes the form document, and the widget writes nothing itself.'
44
+ }, {
45
+ pluginId: BUNDLE_ID
46
+ });
47
+ Aglyn.registerConsoleExtension({
48
+ pluginId: BUNDLE_ID,
49
+ displayName: 'Forms',
50
+ navItems: [
51
+ {
52
+ label: 'Forms',
53
+ href: '/forms',
54
+ // The tab id the console has always keyed this surface's active state
55
+ // on. It carries no release flag: forms is on for every workspace, and
56
+ // a site that switches it off loses this tab with the rest.
57
+ navTabId: 'nav-tab-forms',
58
+ icon: {
59
+ path: mdiEmailFastOutline.path
60
+ },
61
+ ownsSubtree: true,
62
+ header: {
63
+ title: 'Forms',
64
+ icon: {
65
+ path: mdiEmailFastOutline.path
66
+ },
67
+ docsTopic: 'forms'
68
+ },
69
+ Component: FormsConsolePage
70
+ }
71
+ ]
72
+ });
73
+ }
74
+ export * from "./site.js";
75
+
76
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../libs/plugins/forms/src/lib/plugin.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiEmailFastOutline } from '@aglyn/shared-data-mdi'\nimport { lazy } from 'react'\nimport { registerPluginZone } from '@aglyn/aglyn/plugin-manager/plugin-zones'\nimport {\n FORM_CONTACT_FIELDS_ZONE,\n FORM_SUBMISSIONS_ZONE,\n} from './components/form-zones'\nimport { BUNDLE_ID } from './constants/bundle-common'\n\n/** Code-split: the Forms console surface only loads when opened. */\nconst FormsConsolePage = lazy(() => import('./components/forms-console-page'))\n\n/**\n * Console half: the Forms catalog and one form's own surface, served by the\n * shell's generic plugin route.\n *\n * `ownsSubtree` because a form's detail URL names a document id rather than a\n * declared section. Safe to call at console app load — the page is lazy.\n */\nexport function registerFormsConsole(): void {\n registerPluginZone(\n {\n zone: FORM_SUBMISSIONS_ZONE,\n label: 'One form’s submissions',\n surface: 'console',\n description:\n 'On one form’s page, behind the reader’s ask. A widget here reads the submissions to that form alone; it is handed the site and the form and nothing else.',\n },\n // Named, because a spec calls this registrar without the loader.\n { pluginId: BUNDLE_ID },\n )\n registerPluginZone(\n {\n zone: FORM_CONTACT_FIELDS_ZONE,\n label: 'Where a form’s fields save on the person',\n surface: 'console',\n description:\n 'On one form’s page, beside routing and consent. A widget here decides which of the person’s fields each form field saves to and hands the new declaration to `saveFields`; the page writes the form document, and the widget writes nothing itself.',\n },\n { pluginId: BUNDLE_ID },\n )\n Aglyn.registerConsoleExtension({\n pluginId: BUNDLE_ID,\n displayName: 'Forms',\n navItems: [\n {\n label: 'Forms',\n href: '/forms',\n // The tab id the console has always keyed this surface's active state\n // on. It carries no release flag: forms is on for every workspace, and\n // a site that switches it off loses this tab with the rest.\n navTabId: 'nav-tab-forms',\n icon: { path: mdiEmailFastOutline.path },\n ownsSubtree: true,\n header: {\n title: 'Forms',\n icon: { path: mdiEmailFastOutline.path },\n docsTopic: 'forms',\n },\n Component: FormsConsolePage,\n },\n ],\n })\n}\n\nexport * from './site'\n"],"names":["Aglyn","mdiEmailFastOutline","lazy","registerPluginZone","FORM_CONTACT_FIELDS_ZONE","FORM_SUBMISSIONS_ZONE","BUNDLE_ID","FormsConsolePage","registerFormsConsole","zone","label","surface","description","pluginId","registerConsoleExtension","displayName","navItems","href","navTabId","icon","path","ownsSubtree","header","title","docsTopic","Component"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,mBAAmB,QAAQ,yBAAwB;AAC5D,SAASC,IAAI,QAAQ,QAAO;AAC5B,SAASC,kBAAkB,QAAQ,2CAA0C;AAC7E,SACEC,wBAAwB,EACxBC,qBAAqB,QAChB,6BAAyB;AAChC,SAASC,SAAS,QAAQ,+BAA2B;AAErD,kEAAkE,GAClE,MAAMC,mBAAmBL,KAAK,IAAM,MAAM,CAAC;AAE3C;;;;;;CAMC,GACD,OAAO,SAASM;IACdL,mBACE;QACEM,MAAMJ;QACNK,OAAO;QACPC,SAAS;QACTC,aACE;IACJ,GACA,iEAAiE;IACjE;QAAEC,UAAUP;IAAU;IAExBH,mBACE;QACEM,MAAML;QACNM,OAAO;QACPC,SAAS;QACTC,aACE;IACJ,GACA;QAAEC,UAAUP;IAAU;IAExBN,MAAMc,wBAAwB,CAAC;QAC7BD,UAAUP;QACVS,aAAa;QACbC,UAAU;YACR;gBACEN,OAAO;gBACPO,MAAM;gBACN,sEAAsE;gBACtE,uEAAuE;gBACvE,4DAA4D;gBAC5DC,UAAU;gBACVC,MAAM;oBAAEC,MAAMnB,oBAAoBmB,IAAI;gBAAC;gBACvCC,aAAa;gBACbC,QAAQ;oBACNC,OAAO;oBACPJ,MAAM;wBAAEC,MAAMnB,oBAAoBmB,IAAI;oBAAC;oBACvCI,WAAW;gBACb;gBACAC,WAAWlB;YACb;SACD;IACH;AACF;AAEA,cAAc,YAAQ"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import * as Aglyn from '@aglyn/aglyn';
18
+ /**
19
+ * The canvas half: the form and the fields inside it.
20
+ *
21
+ * `formField` ships beside `form` rather than staying with the generic
22
+ * elements because it is not a generic input — it publishes its own
23
+ * name/dataset mapping to the enclosing form through a hidden input, and a
24
+ * field with no form around it submits nowhere.
25
+ */
26
+ export declare const FORMS_BUNDLE: Aglyn.FeatureBundleEntry[];
27
+ /**
28
+ * Forms feature plugin: a canvas element and a console surface, the shape a
29
+ * capability with both halves takes.
30
+ *
31
+ * ## On for every workspace, switchable per site (AGL-3029)
32
+ *
33
+ * A form has two halves, and only one of them is this bundle. The bundle
34
+ * DRAWS the form; its server half is core — `/api/forms/submit` is a core
35
+ * tenant route and `form-contract.ts` a core module the publish path runs —
36
+ * because core may not import a plugin. A switch on the bundle alone would
37
+ * stop only the drawing: a published contact page would render a hole while
38
+ * the endpoint behind it kept answering.
39
+ *
40
+ * So the switch is not the bundle's. `forms` carries `alwaysOnForWorkspace`
41
+ * in the catalog — the catalog and the submissions already stored belong to
42
+ * the workspace, and no workspace switch is offered — and a site switches it
43
+ * off through its ordinary deny-list. Every half asks the site's plugin set
44
+ * about `FORMS_PLUGIN_ID`, never this package: the submit route refuses, the
45
+ * contract check refuses to publish a form or a page carrying one, and the
46
+ * published page stops drawing the element, on the server as on the client.
47
+ *
48
+ * On is not the same as loaded. `requiredSitePlugins` narrows the pre-render
49
+ * set by each node's `pluginId`, so a page with no form on it does not wait
50
+ * for this bundle — which is the saving the move buys, since every page used
51
+ * to carry the form element inside `mui`.
52
+ */
53
+ export declare function registerFormsPlugin(): void;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import * as Aglyn from "@aglyn/aglyn";
17
+ import { mdiEmailFastOutline } from "@aglyn/shared-data-mdi";
18
+ import * as FormComponents from "./components/form.js";
19
+ import { BUNDLE_ID } from "./constants/bundle-common.js";
20
+ /**
21
+ * The canvas half: the form and the fields inside it.
22
+ *
23
+ * `formField` ships beside `form` rather than staying with the generic
24
+ * elements because it is not a generic input — it publishes its own
25
+ * name/dataset mapping to the enclosing form through a hidden input, and a
26
+ * field with no form around it submits nowhere.
27
+ */ export const FORMS_BUNDLE = [
28
+ {
29
+ component: FormComponents.Form,
30
+ schema: FormComponents.formSchema,
31
+ presets: FormComponents.formPresets
32
+ },
33
+ {
34
+ component: FormComponents.FormField,
35
+ schema: FormComponents.formFieldSchema,
36
+ // The composed Contact Section, offered under Sections & Blocks. It hangs
37
+ // off the FIELD entry only because the registry reads presets per entry;
38
+ // what it places is the form above.
39
+ presets: FormComponents.formBlockPresets
40
+ }
41
+ ];
42
+ /**
43
+ * Forms feature plugin: a canvas element and a console surface, the shape a
44
+ * capability with both halves takes.
45
+ *
46
+ * ## On for every workspace, switchable per site (AGL-3029)
47
+ *
48
+ * A form has two halves, and only one of them is this bundle. The bundle
49
+ * DRAWS the form; its server half is core — `/api/forms/submit` is a core
50
+ * tenant route and `form-contract.ts` a core module the publish path runs —
51
+ * because core may not import a plugin. A switch on the bundle alone would
52
+ * stop only the drawing: a published contact page would render a hole while
53
+ * the endpoint behind it kept answering.
54
+ *
55
+ * So the switch is not the bundle's. `forms` carries `alwaysOnForWorkspace`
56
+ * in the catalog — the catalog and the submissions already stored belong to
57
+ * the workspace, and no workspace switch is offered — and a site switches it
58
+ * off through its ordinary deny-list. Every half asks the site's plugin set
59
+ * about `FORMS_PLUGIN_ID`, never this package: the submit route refuses, the
60
+ * contract check refuses to publish a form or a page carrying one, and the
61
+ * published page stops drawing the element, on the server as on the client.
62
+ *
63
+ * On is not the same as loaded. `requiredSitePlugins` narrows the pre-render
64
+ * set by each node's `pluginId`, so a page with no form on it does not wait
65
+ * for this bundle — which is the saving the move buys, since every page used
66
+ * to carry the form element inside `mui`.
67
+ */ export function registerFormsPlugin() {
68
+ // The canvas half only. The console registers the console half through its
69
+ // own `console` surface, and a published page must never load console code
70
+ // (AGL-3116): this runs on every page that places one of these elements.
71
+ if (Aglyn.plugins.getDependency(BUNDLE_ID)) return;
72
+ Aglyn.plugins.addDependency(Aglyn.defineUiFeatureBundle({
73
+ bundleId: BUNDLE_ID,
74
+ displayName: 'Forms',
75
+ description: 'Forms and their fields: contact, signup, survey',
76
+ icon: {
77
+ path: mdiEmailFastOutline.path
78
+ },
79
+ components: FORMS_BUNDLE
80
+ }, Aglyn.components));
81
+ }
82
+
83
+ //# sourceMappingURL=site.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../libs/plugins/forms/src/lib/site.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiEmailFastOutline } from '@aglyn/shared-data-mdi'\nimport * as FormComponents from './components/form'\nimport { BUNDLE_ID } from './constants/bundle-common'\n\n/**\n * The canvas half: the form and the fields inside it.\n *\n * `formField` ships beside `form` rather than staying with the generic\n * elements because it is not a generic input — it publishes its own\n * name/dataset mapping to the enclosing form through a hidden input, and a\n * field with no form around it submits nowhere.\n */\nexport const FORMS_BUNDLE: Aglyn.FeatureBundleEntry[] = [\n {\n component: FormComponents.Form,\n schema: FormComponents.formSchema,\n presets: FormComponents.formPresets,\n },\n {\n component: FormComponents.FormField,\n schema: FormComponents.formFieldSchema,\n // The composed Contact Section, offered under Sections & Blocks. It hangs\n // off the FIELD entry only because the registry reads presets per entry;\n // what it places is the form above.\n presets: FormComponents.formBlockPresets,\n },\n]\n\n/**\n * Forms feature plugin: a canvas element and a console surface, the shape a\n * capability with both halves takes.\n *\n * ## On for every workspace, switchable per site (AGL-3029)\n *\n * A form has two halves, and only one of them is this bundle. The bundle\n * DRAWS the form; its server half is core — `/api/forms/submit` is a core\n * tenant route and `form-contract.ts` a core module the publish path runs —\n * because core may not import a plugin. A switch on the bundle alone would\n * stop only the drawing: a published contact page would render a hole while\n * the endpoint behind it kept answering.\n *\n * So the switch is not the bundle's. `forms` carries `alwaysOnForWorkspace`\n * in the catalog — the catalog and the submissions already stored belong to\n * the workspace, and no workspace switch is offered — and a site switches it\n * off through its ordinary deny-list. Every half asks the site's plugin set\n * about `FORMS_PLUGIN_ID`, never this package: the submit route refuses, the\n * contract check refuses to publish a form or a page carrying one, and the\n * published page stops drawing the element, on the server as on the client.\n *\n * On is not the same as loaded. `requiredSitePlugins` narrows the pre-render\n * set by each node's `pluginId`, so a page with no form on it does not wait\n * for this bundle — which is the saving the move buys, since every page used\n * to carry the form element inside `mui`.\n */\nexport function registerFormsPlugin(): void {\n // The canvas half only. The console registers the console half through its\n // own `console` surface, and a published page must never load console code\n // (AGL-3116): this runs on every page that places one of these elements.\n if (Aglyn.plugins.getDependency(BUNDLE_ID)) return\n Aglyn.plugins.addDependency(\n Aglyn.defineUiFeatureBundle(\n {\n bundleId: BUNDLE_ID,\n displayName: 'Forms',\n description: 'Forms and their fields: contact, signup, survey',\n icon: { path: mdiEmailFastOutline.path },\n components: FORMS_BUNDLE,\n },\n Aglyn.components,\n ),\n )\n}\n"],"names":["Aglyn","mdiEmailFastOutline","FormComponents","BUNDLE_ID","FORMS_BUNDLE","component","Form","schema","formSchema","presets","formPresets","FormField","formFieldSchema","formBlockPresets","registerFormsPlugin","plugins","getDependency","addDependency","defineUiFeatureBundle","bundleId","displayName","description","icon","path","components"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,mBAAmB,QAAQ,yBAAwB;AAC5D,YAAYC,oBAAoB,uBAAmB;AACnD,SAASC,SAAS,QAAQ,+BAA2B;AAErD;;;;;;;CAOC,GACD,OAAO,MAAMC,eAA2C;IACtD;QACEC,WAAWH,eAAeI,IAAI;QAC9BC,QAAQL,eAAeM,UAAU;QACjCC,SAASP,eAAeQ,WAAW;IACrC;IACA;QACEL,WAAWH,eAAeS,SAAS;QACnCJ,QAAQL,eAAeU,eAAe;QACtC,0EAA0E;QAC1E,yEAAyE;QACzE,oCAAoC;QACpCH,SAASP,eAAeW,gBAAgB;IAC1C;CACD,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;CAyBC,GACD,OAAO,SAASC;IACd,2EAA2E;IAC3E,2EAA2E;IAC3E,yEAAyE;IACzE,IAAId,MAAMe,OAAO,CAACC,aAAa,CAACb,YAAY;IAC5CH,MAAMe,OAAO,CAACE,aAAa,CACzBjB,MAAMkB,qBAAqB,CACzB;QACEC,UAAUhB;QACViB,aAAa;QACbC,aAAa;QACbC,MAAM;YAAEC,MAAMtB,oBAAoBsB,IAAI;QAAC;QACvCC,YAAYpB;IACd,GACAJ,MAAMwB,UAAU;AAGtB"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { ComponentId } from '@aglyn/aglyn';
18
+ /**
19
+ * Preset ids ARE namespaced by bundle, unlike component ids: the registry
20
+ * keys presets in one flat record across every registered bundle, so two
21
+ * bundles offering a "contact form" starter would collapse into one entry
22
+ * without the prefix.
23
+ */
24
+ export declare const generatePresetId: (componentId: ComponentId, ...other: string[]) => ComponentId;
25
+ export default generatePresetId;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { BUNDLE_ID } from "../constants/bundle-common.js";
17
+ /**
18
+ * Preset ids ARE namespaced by bundle, unlike component ids: the registry
19
+ * keys presets in one flat record across every registered bundle, so two
20
+ * bundles offering a "contact form" starter would collapse into one entry
21
+ * without the prefix.
22
+ */ export const generatePresetId = (componentId, ...other)=>{
23
+ return `${BUNDLE_ID}:${[
24
+ componentId,
25
+ ...other
26
+ ].join('.')}`;
27
+ };
28
+ export default generatePresetId;
29
+
30
+ //# sourceMappingURL=generate-preset-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/forms/src/lib/utils/generate-preset-id.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ComponentId } from '@aglyn/aglyn'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\n/**\n * Preset ids ARE namespaced by bundle, unlike component ids: the registry\n * keys presets in one flat record across every registered bundle, so two\n * bundles offering a \"contact form\" starter would collapse into one entry\n * without the prefix.\n */\nexport const generatePresetId = (\n componentId: ComponentId,\n ...other: string[]\n): ComponentId => {\n return `${BUNDLE_ID}:${[componentId, ...other].join('.')}`\n}\n\nexport default generatePresetId\n"],"names":["BUNDLE_ID","generatePresetId","componentId","other","join"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAGD,SAASA,SAAS,QAAQ,gCAA4B;AAEtD;;;;;CAKC,GACD,OAAO,MAAMC,mBAAmB,CAC9BC,aACA,GAAGC;IAEH,OAAO,GAAGH,UAAU,CAAC,EAAE;QAACE;WAAgBC;KAAM,CAACC,IAAI,CAAC,MAAM;AAC5D,EAAC;AAED,eAAeH,iBAAgB"}