@aglyn/plugins-workflows 1.0.0-beta.179 → 1.0.0-beta.181

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 (52) hide show
  1. package/package.json +12 -11
  2. package/src/lib/components/automation-trigger-conditions.component.d.ts +43 -0
  3. package/src/lib/components/automation-trigger-conditions.component.js +189 -0
  4. package/src/lib/components/automation-trigger-conditions.component.js.map +1 -0
  5. package/src/lib/components/host-actions-card.component.js +27 -176
  6. package/src/lib/components/host-actions-card.component.js.map +1 -1
  7. package/src/lib/components/org-automation-editor.component.d.ts +51 -0
  8. package/src/lib/components/org-automation-editor.component.js +310 -0
  9. package/src/lib/components/org-automation-editor.component.js.map +1 -0
  10. package/src/lib/components/org-automations-card.component.d.ts +28 -0
  11. package/src/lib/components/org-automations-card.component.js +373 -0
  12. package/src/lib/components/org-automations-card.component.js.map +1 -0
  13. package/src/lib/components/org-site-automation-list.component.d.ts +43 -0
  14. package/src/lib/components/org-site-automation-list.component.js +289 -0
  15. package/src/lib/components/org-site-automation-list.component.js.map +1 -0
  16. package/src/lib/components/site-org-automations-panel.component.d.ts +22 -0
  17. package/src/lib/components/site-org-automations-panel.component.js +201 -0
  18. package/src/lib/components/site-org-automations-panel.component.js.map +1 -0
  19. package/src/lib/components/use-org-automation-step-pickers.d.ts +20 -0
  20. package/src/lib/components/use-org-automation-step-pickers.js +108 -0
  21. package/src/lib/components/use-org-automation-step-pickers.js.map +1 -0
  22. package/src/lib/components/use-org-automations-api.d.ts +16 -0
  23. package/src/lib/components/use-org-automations-api.js +55 -0
  24. package/src/lib/components/use-org-automations-api.js.map +1 -0
  25. package/src/lib/components/workflows-console-page.js +63 -1
  26. package/src/lib/components/workflows-console-page.js.map +1 -1
  27. package/src/lib/components/workflows-console-sections.d.ts +19 -1
  28. package/src/lib/components/workflows-console-sections.js +37 -2
  29. package/src/lib/components/workflows-console-sections.js.map +1 -1
  30. package/src/lib/components/workflows-org-mount.d.ts +52 -0
  31. package/src/lib/components/workflows-org-mount.js +49 -0
  32. package/src/lib/components/workflows-org-mount.js.map +1 -0
  33. package/src/lib/engine/flow-enrollments.d.ts +26 -10
  34. package/src/lib/engine/flow-enrollments.js +14 -7
  35. package/src/lib/engine/flow-enrollments.js.map +1 -1
  36. package/src/lib/engine/run-event-actions.d.ts +57 -4
  37. package/src/lib/engine/run-event-actions.js +119 -19
  38. package/src/lib/engine/run-event-actions.js.map +1 -1
  39. package/src/lib/engine/run-org-automations.d.ts +75 -0
  40. package/src/lib/engine/run-org-automations.js +154 -0
  41. package/src/lib/engine/run-org-automations.js.map +1 -0
  42. package/src/lib/model/org-automations.d.ts +232 -0
  43. package/src/lib/model/org-automations.js +423 -0
  44. package/src/lib/model/org-automations.js.map +1 -0
  45. package/src/lib/plugin.js +26 -1
  46. package/src/lib/plugin.js.map +1 -1
  47. package/src/lib/server/org-automations-routes.d.ts +88 -0
  48. package/src/lib/server/org-automations-routes.js +474 -0
  49. package/src/lib/server/org-automations-routes.js.map +1 -0
  50. package/src/lib/server-console.d.ts +2 -1
  51. package/src/lib/server-console.js +12 -2
  52. package/src/lib/server-console.js.map +1 -1
@@ -0,0 +1,108 @@
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 { datasetPickerOptions } from "@aglyn/aglyn";
18
+ import { scopeCovers } from "@aglyn/aglyn/app-utils/scope-tokens";
19
+ import { useFirestore, useFirestoreCollection } from "@aglyn/tenant-feature-instance";
20
+ /*
21
+ * The MODULE, not the barrel, for the two pure helpers — the cards' specs
22
+ * mock `@aglyn/tenant-feature-instance` wholesale, and a query builder
23
+ * imported through that barrel disappears under the mock.
24
+ */ import { ceilingedWindow, collectionCeiling } from "@aglyn/tenant-feature-instance/hooks/host-collection-queries";
25
+ import { collection, documentId, limit, orderBy, query } from "firebase/firestore";
26
+ import { useMemo } from "react";
27
+ import { EDITOR_OPTION_CEILING } from "./use-automation-step-pickers.js";
28
+ /**
29
+ * WHAT AN ORG AUTOMATION'S STEPS CAN BE POINTED AT (AGL-3302).
30
+ *
31
+ * The site editor's pickers read one site's records; an org automation runs
32
+ * on every site it is placed on, so its pickers read the ORGANIZATION's —
33
+ * the lists, the datasets and the campaign containers — and offer only what
34
+ * every one of those sites can use. A dataset or a campaign shared with some
35
+ * of the org's sites and not the others would resolve on one site and fail
36
+ * the step on the next, so a record is offered only when its own sharing
37
+ * covers the automation's placement (`scopeCovers`). A list belongs to the
38
+ * whole organization and is always offered.
39
+ *
40
+ * The site-only pickers — workflows, overlays, webhooks — are empty: no step
41
+ * an org automation may hold points at one.
42
+ *
43
+ * Read on the same latch and at the same ceiling as the site editor's, and
44
+ * paid only by an author who opens the editor.
45
+ */ export function useOrgAutomationStepPickers(orgId, editorOpened, placement) {
46
+ const firestore = useFirestore();
47
+ /*
48
+ * Unfiltered, ordered by id: the org hub admits only org-wide members, who
49
+ * read every dataset, and `documentId()` ordering is served by the
50
+ * automatic index where a field order would need a composite one.
51
+ */ const { data: datasetRead } = useFirestoreCollection(()=>editorOpened && orgId ? query(collection(firestore, 'orgs', orgId, 'datasets'), orderBy(documentId()), limit(EDITOR_OPTION_CEILING + 1)) : null, [
52
+ firestore,
53
+ orgId,
54
+ editorOpened
55
+ ], {
56
+ idField: '$id'
57
+ });
58
+ const { rows: datasetDocs, truncated: datasetsTruncated } = ceilingedWindow(datasetRead, EDITOR_OPTION_CEILING);
59
+ const { data: listRead } = useFirestoreCollection(()=>editorOpened && orgId ? collectionCeiling(collection(firestore, 'orgs', orgId, 'lists'), EDITOR_OPTION_CEILING) : null, [
60
+ firestore,
61
+ orgId,
62
+ editorOpened
63
+ ], {
64
+ idField: '$id'
65
+ });
66
+ const { rows: listDocs, truncated: listsTruncated } = ceilingedWindow(listRead, EDITOR_OPTION_CEILING);
67
+ const { data: campaignRead } = useFirestoreCollection(()=>editorOpened && orgId ? collectionCeiling(collection(firestore, 'orgs', orgId, 'emailCampaigns'), EDITOR_OPTION_CEILING) : null, [
68
+ firestore,
69
+ orgId,
70
+ editorOpened
71
+ ], {
72
+ idField: '$id'
73
+ });
74
+ const { rows: campaignDocs, truncated: campaignsTruncated } = ceilingedWindow(campaignRead, EDITOR_OPTION_CEILING);
75
+ const pickers = useMemo(()=>{
76
+ const covers = (row)=>scopeCovers(row == null ? void 0 : row.visibleTo, placement);
77
+ return {
78
+ workflowOptions: [],
79
+ overlayOptions: [],
80
+ webhookOptions: [],
81
+ datasetOptions: datasetPickerOptions((datasetDocs != null ? datasetDocs : []).filter(covers)),
82
+ listOptions: (listDocs != null ? listDocs : []).filter((list)=>!list.deletedAt && list.name).map((list)=>({
83
+ id: list.$id,
84
+ name: list.name
85
+ })).sort((a, b)=>a.name.localeCompare(b.name)),
86
+ campaignOptions: (campaignDocs != null ? campaignDocs : []).filter((campaign)=>!campaign.deletedAt && campaign.name).filter(covers).map((campaign)=>({
87
+ id: campaign.$id,
88
+ name: campaign.name
89
+ })).sort((a, b)=>a.name.localeCompare(b.name))
90
+ };
91
+ }, [
92
+ datasetDocs,
93
+ listDocs,
94
+ campaignDocs,
95
+ placement
96
+ ]);
97
+ const truncated = [
98
+ datasetsTruncated ? 'datasets' : null,
99
+ listsTruncated ? 'audiences' : null,
100
+ campaignsTruncated ? 'campaigns' : null
101
+ ].filter((name)=>name !== null);
102
+ return {
103
+ pickers,
104
+ truncated
105
+ };
106
+ }
107
+
108
+ //# sourceMappingURL=use-org-automation-step-pickers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/use-org-automation-step-pickers.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 { datasetPickerOptions } from '@aglyn/aglyn'\nimport { scopeCovers } from '@aglyn/aglyn/app-utils/scope-tokens'\nimport {\n useFirestore,\n useFirestoreCollection,\n} from '@aglyn/tenant-feature-instance'\n/*\n * The MODULE, not the barrel, for the two pure helpers — the cards' specs\n * mock `@aglyn/tenant-feature-instance` wholesale, and a query builder\n * imported through that barrel disappears under the mock.\n */\nimport {\n ceilingedWindow,\n collectionCeiling,\n} from '@aglyn/tenant-feature-instance/hooks/host-collection-queries'\nimport {\n collection,\n documentId,\n limit,\n orderBy,\n query,\n} from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport type { AutomationStepPickers } from './automation-step-fields.component'\nimport {\n type AutomationStepPickerData,\n EDITOR_OPTION_CEILING,\n} from './use-automation-step-pickers'\n\n/**\n * WHAT AN ORG AUTOMATION'S STEPS CAN BE POINTED AT (AGL-3302).\n *\n * The site editor's pickers read one site's records; an org automation runs\n * on every site it is placed on, so its pickers read the ORGANIZATION's —\n * the lists, the datasets and the campaign containers — and offer only what\n * every one of those sites can use. A dataset or a campaign shared with some\n * of the org's sites and not the others would resolve on one site and fail\n * the step on the next, so a record is offered only when its own sharing\n * covers the automation's placement (`scopeCovers`). A list belongs to the\n * whole organization and is always offered.\n *\n * The site-only pickers — workflows, overlays, webhooks — are empty: no step\n * an org automation may hold points at one.\n *\n * Read on the same latch and at the same ceiling as the site editor's, and\n * paid only by an author who opens the editor.\n */\nexport function useOrgAutomationStepPickers(\n orgId: string,\n editorOpened: boolean,\n placement: readonly string[],\n): AutomationStepPickerData {\n const firestore = useFirestore()\n /*\n * Unfiltered, ordered by id: the org hub admits only org-wide members, who\n * read every dataset, and `documentId()` ordering is served by the\n * automatic index where a field order would need a composite one.\n */\n const { data: datasetRead } = useFirestoreCollection<any>(\n () =>\n editorOpened && orgId\n ? query(\n collection(firestore, 'orgs', orgId, 'datasets'),\n orderBy(documentId()),\n limit(EDITOR_OPTION_CEILING + 1),\n )\n : null,\n [firestore, orgId, editorOpened],\n { idField: '$id' },\n )\n const { rows: datasetDocs, truncated: datasetsTruncated } =\n ceilingedWindow<any>(datasetRead, EDITOR_OPTION_CEILING)\n const { data: listRead } = useFirestoreCollection<any>(\n () =>\n editorOpened && orgId\n ? collectionCeiling(\n collection(firestore, 'orgs', orgId, 'lists'),\n EDITOR_OPTION_CEILING,\n )\n : null,\n [firestore, orgId, editorOpened],\n { idField: '$id' },\n )\n const { rows: listDocs, truncated: listsTruncated } = ceilingedWindow<any>(\n listRead,\n EDITOR_OPTION_CEILING,\n )\n const { data: campaignRead } = useFirestoreCollection<any>(\n () =>\n editorOpened && orgId\n ? collectionCeiling(\n collection(firestore, 'orgs', orgId, 'emailCampaigns'),\n EDITOR_OPTION_CEILING,\n )\n : null,\n [firestore, orgId, editorOpened],\n { idField: '$id' },\n )\n const { rows: campaignDocs, truncated: campaignsTruncated } =\n ceilingedWindow<any>(campaignRead, EDITOR_OPTION_CEILING)\n\n const pickers = useMemo<AutomationStepPickers>(() => {\n const covers = (row: any) =>\n scopeCovers(row?.visibleTo as string[] | undefined, placement)\n return {\n workflowOptions: [],\n overlayOptions: [],\n webhookOptions: [],\n datasetOptions: datasetPickerOptions((datasetDocs ?? []).filter(covers)),\n listOptions: (listDocs ?? [])\n .filter((list: any) => !list.deletedAt && list.name)\n .map((list: any) => ({ id: list.$id as string, name: list.name as string }))\n .sort((a, b) => a.name.localeCompare(b.name)),\n campaignOptions: (campaignDocs ?? [])\n .filter((campaign: any) => !campaign.deletedAt && campaign.name)\n .filter(covers)\n .map((campaign: any) => ({\n id: campaign.$id as string,\n name: campaign.name as string,\n }))\n .sort((a, b) => a.name.localeCompare(b.name)),\n }\n }, [datasetDocs, listDocs, campaignDocs, placement])\n\n const truncated = [\n datasetsTruncated ? 'datasets' : null,\n listsTruncated ? 'audiences' : null,\n campaignsTruncated ? 'campaigns' : null,\n ].filter((name): name is string => name !== null)\n return { pickers, truncated }\n}\n"],"names":["datasetPickerOptions","scopeCovers","useFirestore","useFirestoreCollection","ceilingedWindow","collectionCeiling","collection","documentId","limit","orderBy","query","useMemo","EDITOR_OPTION_CEILING","useOrgAutomationStepPickers","orgId","editorOpened","placement","firestore","data","datasetRead","idField","rows","datasetDocs","truncated","datasetsTruncated","listRead","listDocs","listsTruncated","campaignRead","campaignDocs","campaignsTruncated","pickers","covers","row","visibleTo","workflowOptions","overlayOptions","webhookOptions","datasetOptions","filter","listOptions","list","deletedAt","name","map","id","$id","sort","a","b","localeCompare","campaignOptions","campaign"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SAASA,oBAAoB,QAAQ,eAAc;AACnD,SAASC,WAAW,QAAQ,sCAAqC;AACjE,SACEC,YAAY,EACZC,sBAAsB,QACjB,iCAAgC;AACvC;;;;CAIC,GACD,SACEC,eAAe,EACfC,iBAAiB,QACZ,+DAA8D;AACrE,SACEC,UAAU,EACVC,UAAU,EACVC,KAAK,EACLC,OAAO,EACPC,KAAK,QACA,qBAAoB;AAC3B,SAASC,OAAO,QAAQ,QAAO;AAE/B,SAEEC,qBAAqB,QAChB,mCAA+B;AAEtC;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASC,4BACdC,KAAa,EACbC,YAAqB,EACrBC,SAA4B;IAE5B,MAAMC,YAAYf;IAClB;;;;GAIC,GACD,MAAM,EAAEgB,MAAMC,WAAW,EAAE,GAAGhB,uBAC5B,IACEY,gBAAgBD,QACZJ,MACEJ,WAAWW,WAAW,QAAQH,OAAO,aACrCL,QAAQF,eACRC,MAAMI,wBAAwB,MAEhC,MACN;QAACK;QAAWH;QAAOC;KAAa,EAChC;QAAEK,SAAS;IAAM;IAEnB,MAAM,EAAEC,MAAMC,WAAW,EAAEC,WAAWC,iBAAiB,EAAE,GACvDpB,gBAAqBe,aAAaP;IACpC,MAAM,EAAEM,MAAMO,QAAQ,EAAE,GAAGtB,uBACzB,IACEY,gBAAgBD,QACZT,kBACEC,WAAWW,WAAW,QAAQH,OAAO,UACrCF,yBAEF,MACN;QAACK;QAAWH;QAAOC;KAAa,EAChC;QAAEK,SAAS;IAAM;IAEnB,MAAM,EAAEC,MAAMK,QAAQ,EAAEH,WAAWI,cAAc,EAAE,GAAGvB,gBACpDqB,UACAb;IAEF,MAAM,EAAEM,MAAMU,YAAY,EAAE,GAAGzB,uBAC7B,IACEY,gBAAgBD,QACZT,kBACEC,WAAWW,WAAW,QAAQH,OAAO,mBACrCF,yBAEF,MACN;QAACK;QAAWH;QAAOC;KAAa,EAChC;QAAEK,SAAS;IAAM;IAEnB,MAAM,EAAEC,MAAMQ,YAAY,EAAEN,WAAWO,kBAAkB,EAAE,GACzD1B,gBAAqBwB,cAAchB;IAErC,MAAMmB,UAAUpB,QAA+B;QAC7C,MAAMqB,SAAS,CAACC,MACdhC,YAAYgC,uBAAAA,IAAKC,SAAS,EAA0BlB;QACtD,OAAO;YACLmB,iBAAiB,EAAE;YACnBC,gBAAgB,EAAE;YAClBC,gBAAgB,EAAE;YAClBC,gBAAgBtC,qBAAqB,CAACsB,sBAAAA,cAAe,EAAE,EAAEiB,MAAM,CAACP;YAChEQ,aAAa,CAACd,mBAAAA,WAAY,EAAE,EACzBa,MAAM,CAAC,CAACE,OAAc,CAACA,KAAKC,SAAS,IAAID,KAAKE,IAAI,EAClDC,GAAG,CAAC,CAACH,OAAe,CAAA;oBAAEI,IAAIJ,KAAKK,GAAG;oBAAYH,MAAMF,KAAKE,IAAI;gBAAW,CAAA,GACxEI,IAAI,CAAC,CAACC,GAAGC,IAAMD,EAAEL,IAAI,CAACO,aAAa,CAACD,EAAEN,IAAI;YAC7CQ,iBAAiB,CAACtB,uBAAAA,eAAgB,EAAE,EACjCU,MAAM,CAAC,CAACa,WAAkB,CAACA,SAASV,SAAS,IAAIU,SAAST,IAAI,EAC9DJ,MAAM,CAACP,QACPY,GAAG,CAAC,CAACQ,WAAmB,CAAA;oBACvBP,IAAIO,SAASN,GAAG;oBAChBH,MAAMS,SAAST,IAAI;gBACrB,CAAA,GACCI,IAAI,CAAC,CAACC,GAAGC,IAAMD,EAAEL,IAAI,CAACO,aAAa,CAACD,EAAEN,IAAI;QAC/C;IACF,GAAG;QAACrB;QAAaI;QAAUG;QAAcb;KAAU;IAEnD,MAAMO,YAAY;QAChBC,oBAAoB,aAAa;QACjCG,iBAAiB,cAAc;QAC/BG,qBAAqB,cAAc;KACpC,CAACS,MAAM,CAAC,CAACI,OAAyBA,SAAS;IAC5C,OAAO;QAAEZ;QAASR;IAAU;AAC9B"}
@@ -0,0 +1,16 @@
1
+ import { ORG_AUTOMATION_API_ROUTES } from '../model/org-automations';
2
+ /**
3
+ * ONE AUTHORIZED POST TO AN ORG AUTOMATION DOOR (AGL-3302).
4
+ *
5
+ * Every write the org hub and the site panel make goes through a server
6
+ * route — the collection is closed to client writes — so each is the same
7
+ * request against one of the two doors. The route decides who may; this
8
+ * resolves with its answer, and throws the route's own words when it refuses,
9
+ * for the caller's snackbar.
10
+ *
11
+ * The user is read through a ref so the callback keeps one identity while the
12
+ * session object changes beneath it; the token is fetched at call time either
13
+ * way. The path is chosen from the two the plugin serves, never taken from a
14
+ * caller, so a component cannot point the console's credentials elsewhere.
15
+ */
16
+ export declare function useOrgAutomationsApi(): (door: keyof typeof ORG_AUTOMATION_API_ROUTES, body: Record<string, unknown>) => Promise<Record<string, any>>;
@@ -0,0 +1,55 @@
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 { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
18
+ import { useUser } from "@aglyn/tenant-feature-instance";
19
+ import { useCallback, useRef } from "react";
20
+ import { ORG_AUTOMATION_API_ROUTES } from "../model/org-automations.js";
21
+ /**
22
+ * ONE AUTHORIZED POST TO AN ORG AUTOMATION DOOR (AGL-3302).
23
+ *
24
+ * Every write the org hub and the site panel make goes through a server
25
+ * route — the collection is closed to client writes — so each is the same
26
+ * request against one of the two doors. The route decides who may; this
27
+ * resolves with its answer, and throws the route's own words when it refuses,
28
+ * for the caller's snackbar.
29
+ *
30
+ * The user is read through a ref so the callback keeps one identity while the
31
+ * session object changes beneath it; the token is fetched at call time either
32
+ * way. The path is chosen from the two the plugin serves, never taken from a
33
+ * caller, so a component cannot point the console's credentials elsewhere.
34
+ */ export function useOrgAutomationsApi() {
35
+ const { data: user } = useUser();
36
+ const userRef = useRef(user);
37
+ userRef.current = user;
38
+ return useCallback(async (door, body)=>{
39
+ const response = await authorizedFetch(userRef.current, `/api/${ORG_AUTOMATION_API_ROUTES[door]}`, {
40
+ method: 'POST',
41
+ headers: {
42
+ 'Content-Type': 'application/json'
43
+ },
44
+ body: JSON.stringify(body)
45
+ });
46
+ const payload = await response.json().catch(()=>({}));
47
+ if (!response.ok) {
48
+ var _ref;
49
+ throw new Error(String((_ref = payload == null ? void 0 : payload['error']) != null ? _ref : 'The request could not be completed'));
50
+ }
51
+ return payload;
52
+ }, []);
53
+ }
54
+
55
+ //# sourceMappingURL=use-org-automations-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/use-org-automations-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 { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { useCallback, useRef } from 'react'\nimport { ORG_AUTOMATION_API_ROUTES } from '../model/org-automations'\n\n/**\n * ONE AUTHORIZED POST TO AN ORG AUTOMATION DOOR (AGL-3302).\n *\n * Every write the org hub and the site panel make goes through a server\n * route — the collection is closed to client writes — so each is the same\n * request against one of the two doors. The route decides who may; this\n * resolves with its answer, and throws the route's own words when it refuses,\n * for the caller's snackbar.\n *\n * The user is read through a ref so the callback keeps one identity while the\n * session object changes beneath it; the token is fetched at call time either\n * way. The path is chosen from the two the plugin serves, never taken from a\n * caller, so a component cannot point the console's credentials elsewhere.\n */\nexport function useOrgAutomationsApi(): (\n door: keyof typeof ORG_AUTOMATION_API_ROUTES,\n body: Record<string, unknown>,\n) => Promise<Record<string, any>> {\n const { data: user } = useUser()\n const userRef = useRef(user)\n userRef.current = user\n return useCallback(async (door, body) => {\n const response = await authorizedFetch(\n userRef.current as never,\n `/api/${ORG_AUTOMATION_API_ROUTES[door]}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n },\n )\n const payload = (await response.json().catch(() => ({}))) as Record<\n string,\n any\n >\n if (!response.ok) {\n throw new Error(\n String(payload?.['error'] ?? 'The request could not be completed'),\n )\n }\n return payload\n }, [])\n}\n"],"names":["authorizedFetch","useUser","useCallback","useRef","ORG_AUTOMATION_API_ROUTES","useOrgAutomationsApi","data","user","userRef","current","door","body","response","method","headers","JSON","stringify","payload","json","catch","ok","Error","String"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SAASA,eAAe,QAAQ,2CAA0C;AAC1E,SAASC,OAAO,QAAQ,iCAAgC;AACxD,SAASC,WAAW,EAAEC,MAAM,QAAQ,QAAO;AAC3C,SAASC,yBAAyB,QAAQ,8BAA0B;AAEpE;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC;IAId,MAAM,EAAEC,MAAMC,IAAI,EAAE,GAAGN;IACvB,MAAMO,UAAUL,OAAOI;IACvBC,QAAQC,OAAO,GAAGF;IAClB,OAAOL,YAAY,OAAOQ,MAAMC;QAC9B,MAAMC,WAAW,MAAMZ,gBACrBQ,QAAQC,OAAO,EACf,CAAC,KAAK,EAAEL,yBAAyB,CAACM,KAAK,EAAE,EACzC;YACEG,QAAQ;YACRC,SAAS;gBAAE,gBAAgB;YAAmB;YAC9CH,MAAMI,KAAKC,SAAS,CAACL;QACvB;QAEF,MAAMM,UAAW,MAAML,SAASM,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;QAIrD,IAAI,CAACP,SAASQ,EAAE,EAAE;;YAChB,MAAM,IAAIC,MACRC,eAAOL,2BAAAA,OAAS,CAAC,QAAQ,mBAAI;QAEjC;QACA,OAAOA;IACT,GAAG,EAAE;AACP"}
@@ -17,10 +17,15 @@
17
17
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import { HubSections } from "@aglyn/shared-ui-next";
19
19
  import { Stack } from "@mui/material";
20
+ import { useMemo } from "react";
20
21
  import HostActionsCard from "./host-actions-card.component.js";
21
22
  import HostWebhooksCard from "./host-webhooks-card.component.js";
22
23
  import HostWorkflowsCard from "./host-workflows-card.component.js";
24
+ import OrgAutomationsCard from "./org-automations-card.component.js";
25
+ import OrgSiteAutomationList from "./org-site-automation-list.component.js";
23
26
  import RunQuotaLine from "./run-quota-line.component.js";
27
+ import SiteOrgAutomationsPanel from "./site-org-automations-panel.component.js";
28
+ import { workflowsOrgMount } from "./workflows-org-mount.js";
24
29
  /**
25
30
  * The body of one workflows section, built only when that section is the one
26
31
  * being read (AGL-2501).
@@ -63,6 +68,9 @@ import RunQuotaLine from "./run-quota-line.component.js";
63
68
  /*#__PURE__*/ _jsx(HostActionsCard, {
64
69
  hostId: hostId,
65
70
  org: org
71
+ }),
72
+ /*#__PURE__*/ _jsx(SiteOrgAutomationsPanel, {
73
+ hostId: hostId
66
74
  })
67
75
  ]
68
76
  });
@@ -75,6 +83,41 @@ import RunQuotaLine from "./run-quota-line.component.js";
75
83
  return null;
76
84
  }
77
85
  }
86
+ /**
87
+ * The body of one ORGANIZATION-level section (AGL-3302): the org automations,
88
+ * and every site's own workflows, actions and webhooks listed with the site
89
+ * each belongs to.
90
+ *
91
+ * No run allowance line: the allowance is each site's, and an org
92
+ * automation's runs count on the site they run on — each site's own
93
+ * Automation reports its meter.
94
+ */ function orgSectionBody(section, mount, org, canEdit) {
95
+ switch(section){
96
+ case 'automations':
97
+ return /*#__PURE__*/ _jsx(OrgAutomationsCard, {
98
+ mount: mount,
99
+ org: org,
100
+ canEdit: canEdit
101
+ });
102
+ case 'workflows':
103
+ case 'actions':
104
+ return /*#__PURE__*/ _jsx(OrgSiteAutomationList, {
105
+ mount: mount,
106
+ kind: section,
107
+ canRead: true
108
+ });
109
+ case 'webhooks':
110
+ // A webhook holds its site's secret: the rules admit a site's admins
111
+ // and editors, which every org-wide member but a viewer is.
112
+ return /*#__PURE__*/ _jsx(OrgSiteAutomationList, {
113
+ mount: mount,
114
+ kind: "webhooks",
115
+ canRead: canEdit
116
+ });
117
+ default:
118
+ return null;
119
+ }
120
+ }
78
121
  /**
79
122
  * Automation page (AGL-101/148/149 → AGL-395): the automation surface —
80
123
  * workflow builder, event-triggered actions, and webhooks — owned by the
@@ -94,13 +137,32 @@ import RunQuotaLine from "./run-quota-line.component.js";
94
137
  * site and an ACTION belongs to the site too; an interaction belongs to the
95
138
  * document that holds it and is edited on the element, not here.
96
139
  */ export function WorkflowsConsolePage(props) {
97
- const { hostId, org, section, sections, basePath } = props;
140
+ const { hostId, orgMount, org, permissions, section, sections, basePath } = props;
141
+ /*
142
+ * Mounted with no site: the organization's hub (AGL-3302). Memoised so the
143
+ * cards below, which key their listeners on the mount's org, see one object.
144
+ */ const mount = useMemo(()=>hostId == null ? workflowsOrgMount(orgMount, basePath) : null, [
145
+ hostId,
146
+ orgMount,
147
+ basePath
148
+ ]);
98
149
  /*
99
150
  * Nothing until the URL names a section. The shell redirects a bare hub URL
100
151
  * to the landing section and holds a spinner while it does, so this state is
101
152
  * transient — and rendering a default section here instead would pay for its
102
153
  * listens on a URL that is already being replaced.
103
154
  */ if (!section || !(sections == null ? void 0 : sections.length) || !basePath) return null;
155
+ if (hostId == null) {
156
+ // No site and no org to stand in for it: nothing this page can scope.
157
+ if (!mount) return null;
158
+ return /*#__PURE__*/ _jsx(HubSections, {
159
+ sections: sections,
160
+ children: orgSectionBody(section, mount, org, // An org viewer's `editHosts` is false; every other org role's is
161
+ // true. The server routes decide — this keeps a viewer from being
162
+ // offered controls that are about to refuse them.
163
+ (permissions == null ? void 0 : permissions.editHosts) !== false)
164
+ });
165
+ }
104
166
  return /*#__PURE__*/ _jsx(HubSections, {
105
167
  sections: sections,
106
168
  children: sectionBody(section, hostId, org)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/workflows-console-page.tsx"],"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 { AglynOrgBilling, ConsolePluginPageProps } from '@aglyn/aglyn'\nimport { HubSections } from '@aglyn/shared-ui-next'\nimport { Stack } from '@mui/material'\nimport type { ReactNode } from 'react'\nimport HostActionsCard from './host-actions-card.component'\nimport HostWebhooksCard from './host-webhooks-card.component'\nimport HostWorkflowsCard from './host-workflows-card.component'\nimport RunQuotaLine from './run-quota-line.component'\nimport type { WorkflowsConsoleSectionId } from './workflows-console-sections'\n\n/**\n * The body of one workflows section, built only when that section is the one\n * being read (AGL-2501).\n *\n * A function rather than a map of nodes on purpose: a `Record<id, ReactNode>`\n * would CONSTRUCT all three every render, and each card opens its Firestore\n * listens on mount — which is the entire cost this page exists to stop paying.\n * Only the returned branch is ever built.\n */\nfunction sectionBody(\n section: WorkflowsConsoleSectionId,\n hostId: string,\n org: Partial<AglynOrgBilling> | undefined,\n): ReactNode {\n switch (section) {\n case 'workflows':\n return (\n /*\n * `N runs this month · M included` (AGL-2171), which the run-history\n * mockup puts opposite the heading. The quota silently stops\n * automations running once it is reached, and the only place it was\n * reported was the Billing page.\n */\n <Stack spacing={1}>\n <RunQuotaLine hostId={hostId} org={org} counter=\"workflowRuns\" />\n <HostWorkflowsCard hostId={hostId} org={org} />\n </Stack>\n )\n case 'actions':\n return (\n <Stack spacing={1}>\n {/* `actionRunsPerMonth` had NO customer-facing surface at all\n before this — staff panel and usage-alerts only. */}\n <RunQuotaLine hostId={hostId} org={org} counter=\"actionRuns\" />\n <HostActionsCard hostId={hostId} org={org} />\n </Stack>\n )\n case 'webhooks':\n return <HostWebhooksCard hostId={hostId} org={org} />\n default:\n return null\n }\n}\n\n/**\n * Automation page (AGL-101/148/149 → AGL-395): the automation surface —\n * workflow builder, event-triggered actions, and webhooks — owned by the\n * workflows plugin and rendered by the shell's generic plugin route. Each card\n * runs its own entitlement check (workflows / actions / webhooks are distinct\n * plan flags), so the shell's resolved `org` doc flows into all three.\n *\n * Sections are ROUTES (AGL-2501). `HubTabs lazy` already mounted one panel, so\n * this is not a read saving — `workflows-console-read-cost.spec.tsx` was\n * written BEFORE the conversion precisely to hold that line, and reports the\n * same counts after. What routing adds is that the URL names the section: it is\n * linkable, the back button walks sections, the breadcrumb says where you are,\n * and \"mount only what is open\" is structural rather than a `lazy` flag.\n *\n * The section ids are unchanged by the Automation rename: they are the\n * addresses people bookmark and the docs link to. A workflow belongs to the\n * site and an ACTION belongs to the site too; an interaction belongs to the\n * document that holds it and is edited on the element, not here.\n */\nexport function WorkflowsConsolePage(props: ConsolePluginPageProps) {\n const { hostId, org, section, sections, basePath } = props\n\n /*\n * Nothing until the URL names a section. The shell redirects a bare hub URL\n * to the landing section and holds a spinner while it does, so this state is\n * transient — and rendering a default section here instead would pay for its\n * listens on a URL that is already being replaced.\n */\n if (!section || !sections?.length || !basePath) return null\n\n return (\n <HubSections sections={sections}>\n {sectionBody(section as WorkflowsConsoleSectionId, hostId, org)}\n </HubSections>\n )\n}\nWorkflowsConsolePage.displayName = 'WorkflowsConsolePage'\n\nexport default WorkflowsConsolePage\n"],"names":["HubSections","Stack","HostActionsCard","HostWebhooksCard","HostWorkflowsCard","RunQuotaLine","sectionBody","section","hostId","org","spacing","counter","WorkflowsConsolePage","props","sections","basePath","length","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAGA,SAASA,WAAW,QAAQ,wBAAuB;AACnD,SAASC,KAAK,QAAQ,gBAAe;AAErC,OAAOC,qBAAqB,mCAA+B;AAC3D,OAAOC,sBAAsB,oCAAgC;AAC7D,OAAOC,uBAAuB,qCAAiC;AAC/D,OAAOC,kBAAkB,gCAA4B;AAGrD;;;;;;;;CAQC,GACD,SAASC,YACPC,OAAkC,EAClCC,MAAc,EACdC,GAAyC;IAEzC,OAAQF;QACN,KAAK;YACH,OACE;;;;;SAKC,iBACD,MAACN;gBAAMS,SAAS;;kCACd,KAACL;wBAAaG,QAAQA;wBAAQC,KAAKA;wBAAKE,SAAQ;;kCAChD,KAACP;wBAAkBI,QAAQA;wBAAQC,KAAKA;;;;QAG9C,KAAK;YACH,qBACE,MAACR;gBAAMS,SAAS;;kCAGd,KAACL;wBAAaG,QAAQA;wBAAQC,KAAKA;wBAAKE,SAAQ;;kCAChD,KAACT;wBAAgBM,QAAQA;wBAAQC,KAAKA;;;;QAG5C,KAAK;YACH,qBAAO,KAACN;gBAAiBK,QAAQA;gBAAQC,KAAKA;;QAChD;YACE,OAAO;IACX;AACF;AAEA;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASG,qBAAqBC,KAA6B;IAChE,MAAM,EAAEL,MAAM,EAAEC,GAAG,EAAEF,OAAO,EAAEO,QAAQ,EAAEC,QAAQ,EAAE,GAAGF;IAErD;;;;;GAKC,GACD,IAAI,CAACN,WAAW,EAACO,4BAAAA,SAAUE,MAAM,KAAI,CAACD,UAAU,OAAO;IAEvD,qBACE,KAACf;QAAYc,UAAUA;kBACpBR,YAAYC,SAAsCC,QAAQC;;AAGjE;AACAG,qBAAqBK,WAAW,GAAG;AAEnC,eAAeL,qBAAoB"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/workflows-console-page.tsx"],"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 { AglynOrgBilling, ConsolePluginPageProps } from '@aglyn/aglyn'\nimport { HubSections } from '@aglyn/shared-ui-next'\nimport { Stack } from '@mui/material'\nimport { useMemo, type ReactNode } from 'react'\nimport HostActionsCard from './host-actions-card.component'\nimport HostWebhooksCard from './host-webhooks-card.component'\nimport HostWorkflowsCard from './host-workflows-card.component'\nimport OrgAutomationsCard from './org-automations-card.component'\nimport OrgSiteAutomationList from './org-site-automation-list.component'\nimport RunQuotaLine from './run-quota-line.component'\nimport SiteOrgAutomationsPanel from './site-org-automations-panel.component'\nimport type { WorkflowsConsoleSectionId } from './workflows-console-sections'\nimport {\n workflowsOrgMount,\n type WorkflowsOrgMount,\n} from './workflows-org-mount'\n\n/**\n * The body of one workflows section, built only when that section is the one\n * being read (AGL-2501).\n *\n * A function rather than a map of nodes on purpose: a `Record<id, ReactNode>`\n * would CONSTRUCT all three every render, and each card opens its Firestore\n * listens on mount — which is the entire cost this page exists to stop paying.\n * Only the returned branch is ever built.\n */\nfunction sectionBody(\n section: WorkflowsConsoleSectionId,\n hostId: string,\n org: Partial<AglynOrgBilling> | undefined,\n): ReactNode {\n switch (section) {\n case 'workflows':\n return (\n /*\n * `N runs this month · M included` (AGL-2171), which the run-history\n * mockup puts opposite the heading. The quota silently stops\n * automations running once it is reached, and the only place it was\n * reported was the Billing page.\n */\n <Stack spacing={1}>\n <RunQuotaLine hostId={hostId} org={org} counter=\"workflowRuns\" />\n <HostWorkflowsCard hostId={hostId} org={org} />\n </Stack>\n )\n case 'actions':\n return (\n <Stack spacing={1}>\n {/* `actionRunsPerMonth` had NO customer-facing surface at all\n before this — staff panel and usage-alerts only. */}\n <RunQuotaLine hostId={hostId} org={org} counter=\"actionRuns\" />\n <HostActionsCard hostId={hostId} org={org} />\n {/* What the organization runs on this site beside the site's own\n actions, and the site's pause for each (AGL-3302). */}\n <SiteOrgAutomationsPanel hostId={hostId} />\n </Stack>\n )\n case 'webhooks':\n return <HostWebhooksCard hostId={hostId} org={org} />\n default:\n return null\n }\n}\n\n/**\n * The body of one ORGANIZATION-level section (AGL-3302): the org automations,\n * and every site's own workflows, actions and webhooks listed with the site\n * each belongs to.\n *\n * No run allowance line: the allowance is each site's, and an org\n * automation's runs count on the site they run on — each site's own\n * Automation reports its meter.\n */\nfunction orgSectionBody(\n section: WorkflowsConsoleSectionId,\n mount: WorkflowsOrgMount,\n org: Partial<AglynOrgBilling> | undefined,\n canEdit: boolean,\n): ReactNode {\n switch (section) {\n case 'automations':\n return <OrgAutomationsCard mount={mount} org={org} canEdit={canEdit} />\n case 'workflows':\n case 'actions':\n return <OrgSiteAutomationList mount={mount} kind={section} canRead />\n case 'webhooks':\n // A webhook holds its site's secret: the rules admit a site's admins\n // and editors, which every org-wide member but a viewer is.\n return (\n <OrgSiteAutomationList mount={mount} kind=\"webhooks\" canRead={canEdit} />\n )\n default:\n return null\n }\n}\n\n/**\n * Automation page (AGL-101/148/149 → AGL-395): the automation surface —\n * workflow builder, event-triggered actions, and webhooks — owned by the\n * workflows plugin and rendered by the shell's generic plugin route. Each card\n * runs its own entitlement check (workflows / actions / webhooks are distinct\n * plan flags), so the shell's resolved `org` doc flows into all three.\n *\n * Sections are ROUTES (AGL-2501). `HubTabs lazy` already mounted one panel, so\n * this is not a read saving — `workflows-console-read-cost.spec.tsx` was\n * written BEFORE the conversion precisely to hold that line, and reports the\n * same counts after. What routing adds is that the URL names the section: it is\n * linkable, the back button walks sections, the breadcrumb says where you are,\n * and \"mount only what is open\" is structural rather than a `lazy` flag.\n *\n * The section ids are unchanged by the Automation rename: they are the\n * addresses people bookmark and the docs link to. A workflow belongs to the\n * site and an ACTION belongs to the site too; an interaction belongs to the\n * document that holds it and is edited on the element, not here.\n */\nexport function WorkflowsConsolePage(props: ConsolePluginPageProps) {\n const { hostId, orgMount, org, permissions, section, sections, basePath } =\n props\n /*\n * Mounted with no site: the organization's hub (AGL-3302). Memoised so the\n * cards below, which key their listeners on the mount's org, see one object.\n */\n const mount = useMemo(\n () => (hostId == null ? workflowsOrgMount(orgMount, basePath) : null),\n [hostId, orgMount, basePath],\n )\n\n /*\n * Nothing until the URL names a section. The shell redirects a bare hub URL\n * to the landing section and holds a spinner while it does, so this state is\n * transient — and rendering a default section here instead would pay for its\n * listens on a URL that is already being replaced.\n */\n if (!section || !sections?.length || !basePath) return null\n\n if (hostId == null) {\n // No site and no org to stand in for it: nothing this page can scope.\n if (!mount) return null\n return (\n <HubSections sections={sections}>\n {orgSectionBody(\n section as WorkflowsConsoleSectionId,\n mount,\n org,\n // An org viewer's `editHosts` is false; every other org role's is\n // true. The server routes decide — this keeps a viewer from being\n // offered controls that are about to refuse them.\n permissions?.editHosts !== false,\n )}\n </HubSections>\n )\n }\n\n return (\n <HubSections sections={sections}>\n {sectionBody(section as WorkflowsConsoleSectionId, hostId, org)}\n </HubSections>\n )\n}\nWorkflowsConsolePage.displayName = 'WorkflowsConsolePage'\n\nexport default WorkflowsConsolePage\n"],"names":["HubSections","Stack","useMemo","HostActionsCard","HostWebhooksCard","HostWorkflowsCard","OrgAutomationsCard","OrgSiteAutomationList","RunQuotaLine","SiteOrgAutomationsPanel","workflowsOrgMount","sectionBody","section","hostId","org","spacing","counter","orgSectionBody","mount","canEdit","kind","canRead","WorkflowsConsolePage","props","orgMount","permissions","sections","basePath","length","editHosts","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAGA,SAASA,WAAW,QAAQ,wBAAuB;AACnD,SAASC,KAAK,QAAQ,gBAAe;AACrC,SAASC,OAAO,QAAwB,QAAO;AAC/C,OAAOC,qBAAqB,mCAA+B;AAC3D,OAAOC,sBAAsB,oCAAgC;AAC7D,OAAOC,uBAAuB,qCAAiC;AAC/D,OAAOC,wBAAwB,sCAAkC;AACjE,OAAOC,2BAA2B,0CAAsC;AACxE,OAAOC,kBAAkB,gCAA4B;AACrD,OAAOC,6BAA6B,4CAAwC;AAE5E,SACEC,iBAAiB,QAEZ,2BAAuB;AAE9B;;;;;;;;CAQC,GACD,SAASC,YACPC,OAAkC,EAClCC,MAAc,EACdC,GAAyC;IAEzC,OAAQF;QACN,KAAK;YACH,OACE;;;;;SAKC,iBACD,MAACX;gBAAMc,SAAS;;kCACd,KAACP;wBAAaK,QAAQA;wBAAQC,KAAKA;wBAAKE,SAAQ;;kCAChD,KAACX;wBAAkBQ,QAAQA;wBAAQC,KAAKA;;;;QAG9C,KAAK;YACH,qBACE,MAACb;gBAAMc,SAAS;;kCAGd,KAACP;wBAAaK,QAAQA;wBAAQC,KAAKA;wBAAKE,SAAQ;;kCAChD,KAACb;wBAAgBU,QAAQA;wBAAQC,KAAKA;;kCAGtC,KAACL;wBAAwBI,QAAQA;;;;QAGvC,KAAK;YACH,qBAAO,KAACT;gBAAiBS,QAAQA;gBAAQC,KAAKA;;QAChD;YACE,OAAO;IACX;AACF;AAEA;;;;;;;;CAQC,GACD,SAASG,eACPL,OAAkC,EAClCM,KAAwB,EACxBJ,GAAyC,EACzCK,OAAgB;IAEhB,OAAQP;QACN,KAAK;YACH,qBAAO,KAACN;gBAAmBY,OAAOA;gBAAOJ,KAAKA;gBAAKK,SAASA;;QAC9D,KAAK;QACL,KAAK;YACH,qBAAO,KAACZ;gBAAsBW,OAAOA;gBAAOE,MAAMR;gBAASS,OAAO;;QACpE,KAAK;YACH,qEAAqE;YACrE,4DAA4D;YAC5D,qBACE,KAACd;gBAAsBW,OAAOA;gBAAOE,MAAK;gBAAWC,SAASF;;QAElE;YACE,OAAO;IACX;AACF;AAEA;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASG,qBAAqBC,KAA6B;IAChE,MAAM,EAAEV,MAAM,EAAEW,QAAQ,EAAEV,GAAG,EAAEW,WAAW,EAAEb,OAAO,EAAEc,QAAQ,EAAEC,QAAQ,EAAE,GACvEJ;IACF;;;GAGC,GACD,MAAML,QAAQhB,QACZ,IAAOW,UAAU,OAAOH,kBAAkBc,UAAUG,YAAY,MAChE;QAACd;QAAQW;QAAUG;KAAS;IAG9B;;;;;GAKC,GACD,IAAI,CAACf,WAAW,EAACc,4BAAAA,SAAUE,MAAM,KAAI,CAACD,UAAU,OAAO;IAEvD,IAAId,UAAU,MAAM;QAClB,sEAAsE;QACtE,IAAI,CAACK,OAAO,OAAO;QACnB,qBACE,KAAClB;YAAY0B,UAAUA;sBACpBT,eACCL,SACAM,OACAJ,KACA,kEAAkE;YAClE,kEAAkE;YAClE,kDAAkD;YAClDW,CAAAA,+BAAAA,YAAaI,SAAS,MAAK;;IAInC;IAEA,qBACE,KAAC7B;QAAY0B,UAAUA;kBACpBf,YAAYC,SAAsCC,QAAQC;;AAGjE;AACAQ,qBAAqBQ,WAAW,GAAG;AAEnC,eAAeR,qBAAoB"}
@@ -15,7 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  import type { ConsoleNavSection } from '@aglyn/aglyn';
18
- export type WorkflowsConsoleSectionId = 'workflows' | 'actions' | 'webhooks';
18
+ export type WorkflowsConsoleSectionId = 'workflows' | 'actions' | 'webhooks' | 'automations';
19
19
  /**
20
20
  * The workflows console's sections, in rail order (AGL-2501).
21
21
  *
@@ -32,3 +32,21 @@ export type WorkflowsConsoleSectionId = 'workflows' | 'actions' | 'webhooks';
32
32
  * plan flags, and a plan is not a release flag.
33
33
  */
34
34
  export declare const WORKFLOWS_CONSOLE_SECTIONS: readonly ConsoleNavSection[];
35
+ /**
36
+ * The ORGANIZATION-level Automation hub's sections, at `/[orgSlug]/automation`
37
+ * (AGL-3302).
38
+ *
39
+ * Org automations come first because they are the one thing that lives here
40
+ * and nowhere else: the organization writes them once and places them on the
41
+ * sites it chooses. The other three are the sites' own workflows, actions and
42
+ * webhooks listed side by side with the site each belongs to — each row opens
43
+ * in that site's hub, where it is edited, because a workflow calls its site's
44
+ * functions and a webhook holds its site's secret.
45
+ *
46
+ * The ids are the site rail's for the three it shares, so a link built for
47
+ * one level reads the same at the other. `automations` takes the `actions`
48
+ * entitlement: an org automation is built from the actions builder's steps,
49
+ * so the plan that carries one carries the other, and the shell draws the
50
+ * section locked — with its upgrade notice — for a plan without it.
51
+ */
52
+ export declare const WORKFLOWS_ORG_CONSOLE_SECTIONS: readonly ConsoleNavSection[];
@@ -40,11 +40,46 @@
40
40
  id: 'webhooks',
41
41
  label: 'Webhooks'
42
42
  }
43
- ] /*
43
+ ];
44
+ /*
44
45
  * Rail ORDER decides where `/workflows` lands: the shell redirects a bare hub
45
46
  * URL to the first section in this list the reader may open (AGL-2501). There
46
47
  * is deliberately no separate default constant — a second place to say which
47
48
  * section is first is a second place for it to disagree with the rail.
48
- */ ;
49
+ */ /**
50
+ * The ORGANIZATION-level Automation hub's sections, at `/[orgSlug]/automation`
51
+ * (AGL-3302).
52
+ *
53
+ * Org automations come first because they are the one thing that lives here
54
+ * and nowhere else: the organization writes them once and places them on the
55
+ * sites it chooses. The other three are the sites' own workflows, actions and
56
+ * webhooks listed side by side with the site each belongs to — each row opens
57
+ * in that site's hub, where it is edited, because a workflow calls its site's
58
+ * functions and a webhook holds its site's secret.
59
+ *
60
+ * The ids are the site rail's for the three it shares, so a link built for
61
+ * one level reads the same at the other. `automations` takes the `actions`
62
+ * entitlement: an org automation is built from the actions builder's steps,
63
+ * so the plan that carries one carries the other, and the shell draws the
64
+ * section locked — with its upgrade notice — for a plan without it.
65
+ */ export const WORKFLOWS_ORG_CONSOLE_SECTIONS = [
66
+ {
67
+ id: 'automations',
68
+ label: 'Org automations',
69
+ featureFlag: 'actions'
70
+ },
71
+ {
72
+ id: 'workflows',
73
+ label: 'Workflows'
74
+ },
75
+ {
76
+ id: 'actions',
77
+ label: 'Actions'
78
+ },
79
+ {
80
+ id: 'webhooks',
81
+ label: 'Webhooks'
82
+ }
83
+ ];
49
84
 
50
85
  //# sourceMappingURL=workflows-console-sections.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/workflows-console-sections.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 { ConsoleNavSection } from '@aglyn/aglyn'\n\nexport type WorkflowsConsoleSectionId = 'workflows' | 'actions' | 'webhooks'\n\n/**\n * The workflows console's sections, in rail order (AGL-2501).\n *\n * One list, read twice and never copied: `plugin.ts` registers it on the nav\n * item so the shell can route and gate each section, and the page switches its\n * body on the id the shell resolves back.\n *\n * Ids are the `?tab=` ids this page already deep-linked by, kept deliberately\n * so a bookmark that named a tab names the same section as a route.\n *\n * No `navTabId` on any of them: they inherit the Workflows nav item's gate,\n * which is `nav-tab-workflows`. The per-card ENTITLEMENT checks are unchanged\n * and still live in the cards — workflows, actions and webhooks are distinct\n * plan flags, and a plan is not a release flag.\n */\nexport const WORKFLOWS_CONSOLE_SECTIONS: readonly ConsoleNavSection[] = [\n { id: 'workflows', label: 'Workflows' },\n { id: 'actions', label: 'Actions' },\n { id: 'webhooks', label: 'Webhooks' },\n]\n\n/*\n * Rail ORDER decides where `/workflows` lands: the shell redirects a bare hub\n * URL to the first section in this list the reader may open (AGL-2501). There\n * is deliberately no separate default constant — a second place to say which\n * section is first is a second place for it to disagree with the rail.\n */\n"],"names":["WORKFLOWS_CONSOLE_SECTIONS","id","label"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAMD;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMA,6BAA2D;IACtE;QAAEC,IAAI;QAAaC,OAAO;IAAY;IACtC;QAAED,IAAI;QAAWC,OAAO;IAAU;IAClC;QAAED,IAAI;QAAYC,OAAO;IAAW;CACrC,CAED;;;;;CAKC,IAPA"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/workflows-console-sections.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 { ConsoleNavSection } from '@aglyn/aglyn'\n\nexport type WorkflowsConsoleSectionId =\n | 'workflows'\n | 'actions'\n | 'webhooks'\n // The ORGANIZATION hub's own section (AGL-3302); no site rail carries it.\n | 'automations'\n\n/**\n * The workflows console's sections, in rail order (AGL-2501).\n *\n * One list, read twice and never copied: `plugin.ts` registers it on the nav\n * item so the shell can route and gate each section, and the page switches its\n * body on the id the shell resolves back.\n *\n * Ids are the `?tab=` ids this page already deep-linked by, kept deliberately\n * so a bookmark that named a tab names the same section as a route.\n *\n * No `navTabId` on any of them: they inherit the Workflows nav item's gate,\n * which is `nav-tab-workflows`. The per-card ENTITLEMENT checks are unchanged\n * and still live in the cards — workflows, actions and webhooks are distinct\n * plan flags, and a plan is not a release flag.\n */\nexport const WORKFLOWS_CONSOLE_SECTIONS: readonly ConsoleNavSection[] = [\n { id: 'workflows', label: 'Workflows' },\n { id: 'actions', label: 'Actions' },\n { id: 'webhooks', label: 'Webhooks' },\n]\n\n/*\n * Rail ORDER decides where `/workflows` lands: the shell redirects a bare hub\n * URL to the first section in this list the reader may open (AGL-2501). There\n * is deliberately no separate default constant — a second place to say which\n * section is first is a second place for it to disagree with the rail.\n */\n\n/**\n * The ORGANIZATION-level Automation hub's sections, at `/[orgSlug]/automation`\n * (AGL-3302).\n *\n * Org automations come first because they are the one thing that lives here\n * and nowhere else: the organization writes them once and places them on the\n * sites it chooses. The other three are the sites' own workflows, actions and\n * webhooks listed side by side with the site each belongs to — each row opens\n * in that site's hub, where it is edited, because a workflow calls its site's\n * functions and a webhook holds its site's secret.\n *\n * The ids are the site rail's for the three it shares, so a link built for\n * one level reads the same at the other. `automations` takes the `actions`\n * entitlement: an org automation is built from the actions builder's steps,\n * so the plan that carries one carries the other, and the shell draws the\n * section locked — with its upgrade notice — for a plan without it.\n */\nexport const WORKFLOWS_ORG_CONSOLE_SECTIONS: readonly ConsoleNavSection[] = [\n { id: 'automations', label: 'Org automations', featureFlag: 'actions' },\n { id: 'workflows', label: 'Workflows' },\n { id: 'actions', label: 'Actions' },\n { id: 'webhooks', label: 'Webhooks' },\n]\n"],"names":["WORKFLOWS_CONSOLE_SECTIONS","id","label","WORKFLOWS_ORG_CONSOLE_SECTIONS","featureFlag"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAWD;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMA,6BAA2D;IACtE;QAAEC,IAAI;QAAaC,OAAO;IAAY;IACtC;QAAED,IAAI;QAAWC,OAAO;IAAU;IAClC;QAAED,IAAI;QAAYC,OAAO;IAAW;CACrC,CAAA;AAED;;;;;CAKC,GAED;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,MAAMC,iCAA+D;IAC1E;QAAEF,IAAI;QAAeC,OAAO;QAAmBE,aAAa;IAAU;IACtE;QAAEH,IAAI;QAAaC,OAAO;IAAY;IACtC;QAAED,IAAI;QAAWC,OAAO;IAAU;IAClC;QAAED,IAAI;QAAYC,OAAO;IAAW;CACrC,CAAA"}
@@ -0,0 +1,52 @@
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 { ConsolePluginOrgHost, ConsolePluginOrgMount } from '@aglyn/aglyn';
18
+ /**
19
+ * The organization the Automation hub is mounted over at `/[orgSlug]/automation`
20
+ * (AGL-3302): the shell's org mount, with the hub's own path beside it.
21
+ *
22
+ * Handed to each org card as a prop rather than through a context — the org
23
+ * cards are the page's direct children, and a card that needs no site never
24
+ * has to wonder whether it is under one.
25
+ */
26
+ export interface WorkflowsOrgMount {
27
+ orgId: string;
28
+ orgSlug: string;
29
+ /** The org's sites, as the shell resolved them. */
30
+ hosts: readonly ConsolePluginOrgHost[];
31
+ /** False until `hosts` has settled; an empty list before then means nothing. */
32
+ hostsReady: boolean;
33
+ /** `/[orgSlug]/hosts` — every site's own hub hangs beneath it. */
34
+ hostsPath: string;
35
+ /** The org Automation hub's own path, `/[orgSlug]/automation`. */
36
+ basePath: string;
37
+ }
38
+ /** The shell's org mount, as the Automation cards read it. */
39
+ export declare function workflowsOrgMount(orgMount: ConsolePluginOrgMount | undefined, basePath: string | undefined): WorkflowsOrgMount | null;
40
+ /** A site's display name from the mount, or its id when the mount lacks it. */
41
+ export declare function orgSiteName(mount: Pick<WorkflowsOrgMount, 'hosts'>, hostId: string): string;
42
+ /**
43
+ * One site's own Automation hub — `/[orgSlug]/hosts/{subdomain}/automation`,
44
+ * optionally at one of its sections — or `null` when the site is not in the
45
+ * mount or has no subdomain yet, which a row names and does not link.
46
+ */
47
+ export declare function orgSiteAutomationPath(mount: Pick<WorkflowsOrgMount, 'hosts' | 'hostsPath'>, hostId: string, section?: string): string | null;
48
+ /** The org's sites as picker options, by name. */
49
+ export declare function orgSiteOptions(mount: Pick<WorkflowsOrgMount, 'hosts'>): Array<{
50
+ value: string;
51
+ label: string;
52
+ }>;
@@ -0,0 +1,49 @@
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
+ */ /** The shell's org mount, as the Automation cards read it. */ export function workflowsOrgMount(orgMount, basePath) {
17
+ if (!orgMount || !basePath) return null;
18
+ return {
19
+ orgId: orgMount.orgId,
20
+ orgSlug: orgMount.orgSlug,
21
+ hosts: orgMount.hosts,
22
+ hostsReady: orgMount.hostsReady,
23
+ hostsPath: orgMount.hostsPath,
24
+ basePath
25
+ };
26
+ }
27
+ /** A site's display name from the mount, or its id when the mount lacks it. */ export function orgSiteName(mount, hostId) {
28
+ var _mount_hosts_find;
29
+ return ((_mount_hosts_find = mount.hosts.find((host)=>host.id === hostId)) == null ? void 0 : _mount_hosts_find.name) || hostId;
30
+ }
31
+ /**
32
+ * One site's own Automation hub — `/[orgSlug]/hosts/{subdomain}/automation`,
33
+ * optionally at one of its sections — or `null` when the site is not in the
34
+ * mount or has no subdomain yet, which a row names and does not link.
35
+ */ export function orgSiteAutomationPath(mount, hostId, section) {
36
+ var _mount_hosts_find;
37
+ const subdomain = (_mount_hosts_find = mount.hosts.find((host)=>host.id === hostId)) == null ? void 0 : _mount_hosts_find.subdomain;
38
+ if (!subdomain) return null;
39
+ const hub = `${mount.hostsPath}/${encodeURIComponent(subdomain)}/automation`;
40
+ return section ? `${hub}/${section}` : hub;
41
+ }
42
+ /** The org's sites as picker options, by name. */ export function orgSiteOptions(mount) {
43
+ return mount.hosts.map((host)=>({
44
+ value: host.id,
45
+ label: host.name || host.subdomain || host.id
46
+ }));
47
+ }
48
+
49
+ //# sourceMappingURL=workflows-org-mount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/workflows-org-mount.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 { ConsolePluginOrgHost, ConsolePluginOrgMount } from '@aglyn/aglyn'\n\n/**\n * The organization the Automation hub is mounted over at `/[orgSlug]/automation`\n * (AGL-3302): the shell's org mount, with the hub's own path beside it.\n *\n * Handed to each org card as a prop rather than through a context — the org\n * cards are the page's direct children, and a card that needs no site never\n * has to wonder whether it is under one.\n */\nexport interface WorkflowsOrgMount {\n orgId: string\n orgSlug: string\n /** The org's sites, as the shell resolved them. */\n hosts: readonly ConsolePluginOrgHost[]\n /** False until `hosts` has settled; an empty list before then means nothing. */\n hostsReady: boolean\n /** `/[orgSlug]/hosts` — every site's own hub hangs beneath it. */\n hostsPath: string\n /** The org Automation hub's own path, `/[orgSlug]/automation`. */\n basePath: string\n}\n\n/** The shell's org mount, as the Automation cards read it. */\nexport function workflowsOrgMount(\n orgMount: ConsolePluginOrgMount | undefined,\n basePath: string | undefined,\n): WorkflowsOrgMount | null {\n if (!orgMount || !basePath) return null\n return {\n orgId: orgMount.orgId,\n orgSlug: orgMount.orgSlug,\n hosts: orgMount.hosts,\n hostsReady: orgMount.hostsReady,\n hostsPath: orgMount.hostsPath,\n basePath,\n }\n}\n\n/** A site's display name from the mount, or its id when the mount lacks it. */\nexport function orgSiteName(\n mount: Pick<WorkflowsOrgMount, 'hosts'>,\n hostId: string,\n): string {\n return mount.hosts.find((host) => host.id === hostId)?.name || hostId\n}\n\n/**\n * One site's own Automation hub — `/[orgSlug]/hosts/{subdomain}/automation`,\n * optionally at one of its sections — or `null` when the site is not in the\n * mount or has no subdomain yet, which a row names and does not link.\n */\nexport function orgSiteAutomationPath(\n mount: Pick<WorkflowsOrgMount, 'hosts' | 'hostsPath'>,\n hostId: string,\n section?: string,\n): string | null {\n const subdomain = mount.hosts.find((host) => host.id === hostId)?.subdomain\n if (!subdomain) return null\n const hub = `${mount.hostsPath}/${encodeURIComponent(subdomain)}/automation`\n return section ? `${hub}/${section}` : hub\n}\n\n/** The org's sites as picker options, by name. */\nexport function orgSiteOptions(\n mount: Pick<WorkflowsOrgMount, 'hosts'>,\n): Array<{ value: string; label: string }> {\n return mount.hosts.map((host) => ({\n value: host.id,\n label: host.name || host.subdomain || host.id,\n }))\n}\n"],"names":["workflowsOrgMount","orgMount","basePath","orgId","orgSlug","hosts","hostsReady","hostsPath","orgSiteName","mount","hostId","find","host","id","name","orgSiteAutomationPath","section","subdomain","hub","encodeURIComponent","orgSiteOptions","map","value","label"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAyBD,4DAA4D,GAC5D,OAAO,SAASA,kBACdC,QAA2C,EAC3CC,QAA4B;IAE5B,IAAI,CAACD,YAAY,CAACC,UAAU,OAAO;IACnC,OAAO;QACLC,OAAOF,SAASE,KAAK;QACrBC,SAASH,SAASG,OAAO;QACzBC,OAAOJ,SAASI,KAAK;QACrBC,YAAYL,SAASK,UAAU;QAC/BC,WAAWN,SAASM,SAAS;QAC7BL;IACF;AACF;AAEA,6EAA6E,GAC7E,OAAO,SAASM,YACdC,KAAuC,EACvCC,MAAc;QAEPD;IAAP,OAAOA,EAAAA,oBAAAA,MAAMJ,KAAK,CAACM,IAAI,CAAC,CAACC,OAASA,KAAKC,EAAE,KAAKH,4BAAvCD,kBAAgDK,IAAI,KAAIJ;AACjE;AAEA;;;;CAIC,GACD,OAAO,SAASK,sBACdN,KAAqD,EACrDC,MAAc,EACdM,OAAgB;QAEEP;IAAlB,MAAMQ,aAAYR,oBAAAA,MAAMJ,KAAK,CAACM,IAAI,CAAC,CAACC,OAASA,KAAKC,EAAE,KAAKH,4BAAvCD,kBAAgDQ,SAAS;IAC3E,IAAI,CAACA,WAAW,OAAO;IACvB,MAAMC,MAAM,GAAGT,MAAMF,SAAS,CAAC,CAAC,EAAEY,mBAAmBF,WAAW,WAAW,CAAC;IAC5E,OAAOD,UAAU,GAAGE,IAAI,CAAC,EAAEF,SAAS,GAAGE;AACzC;AAEA,gDAAgD,GAChD,OAAO,SAASE,eACdX,KAAuC;IAEvC,OAAOA,MAAMJ,KAAK,CAACgB,GAAG,CAAC,CAACT,OAAU,CAAA;YAChCU,OAAOV,KAAKC,EAAE;YACdU,OAAOX,KAAKE,IAAI,IAAIF,KAAKK,SAAS,IAAIL,KAAKC,EAAE;QAC/C,CAAA;AACF"}
@@ -17,10 +17,17 @@
17
17
  import type { PluginJobHostGate } from '@aglyn/aglyn/server';
18
18
  import type { WorkflowStep } from './workflow-steps';
19
19
  /**
20
- * `hosts/{hostId}/flowEnrollments/{actionId__personKey}` for an action, and
21
- * `{workflow-<workflowId>__personKey}` for a workflow.
20
+ * `hosts/{hostId}/flowEnrollments/{actionId__personKey}` for an action,
21
+ * `{workflow-<workflowId>__personKey}` for a workflow, and
22
+ * `{org-<automationId>__personKey}` for an org automation waiting on the site
23
+ * it ran on.
22
24
  */
23
25
  export declare const FLOW_ENROLLMENTS_SUBCOLLECTION = "flowEnrollments";
26
+ /**
27
+ * What is waiting, when it is not a site action: `workflow` for a workflow's
28
+ * run and `org` for an org automation's (AGL-3302).
29
+ */
30
+ export type FlowEnrollmentAutomation = 'workflow' | 'org';
24
31
  /**
25
32
  * Documents one sweep may READ across every site.
26
33
  *
@@ -62,12 +69,19 @@ export type FlowEnrollmentEnding =
62
69
  export interface FlowEnrollment {
63
70
  hostId: string;
64
71
  /**
65
- * What is waiting: `workflow` for a workflow's run, absent for an action's
66
- * — which is every enrollment written before a workflow could wait, so an
67
- * absent field is read as an action for as long as those rows exist.
72
+ * What is waiting: `workflow` for a workflow's run, `org` for an org
73
+ * automation's, absent for an action's — which is every enrollment written
74
+ * before a workflow could wait, so an absent field is read as an action for
75
+ * as long as those rows exist.
76
+ */
77
+ automation?: FlowEnrollmentAutomation;
78
+ /**
79
+ * The organization whose automation this is, on an `org` enrollment: the
80
+ * resume re-reads `orgs/{orgId}/automations/{actionId}`, and refuses to
81
+ * continue for a site that has since left the organization.
68
82
  */
69
- automation?: 'workflow';
70
- /** The automation's document id: the action's, or the workflow's. */
83
+ orgId?: string;
84
+ /** The automation's document id: the action's, the workflow's or the org automation's. */
71
85
  actionId: string;
72
86
  actionName: string;
73
87
  status: FlowEnrollmentStatus;
@@ -125,11 +139,13 @@ export interface FlowEnrollment {
125
139
  * enrollments would key on something narrower than the person (the cart, the
126
140
  * order), which is a change to this function and to nothing else.
127
141
  */
128
- export declare function flowEnrollmentId(actionId: string, key: string, automation?: 'workflow'): string;
142
+ export declare function flowEnrollmentId(actionId: string, key: string, automation?: FlowEnrollmentAutomation): string;
129
143
  export interface EnrollInFlowOptions {
130
144
  hostId: string;
131
- /** `workflow` for a workflow's run; absent for an action's. */
132
- automation?: 'workflow';
145
+ /** `workflow` for a workflow's run, `org` for an org automation's; absent for an action's. */
146
+ automation?: FlowEnrollmentAutomation;
147
+ /** The owning organization, on an `org` enrollment. */
148
+ orgId?: string;
133
149
  /** The automation's document id. */
134
150
  actionId: string;
135
151
  action: {