@aglyn/plugins-logic 1.0.0-beta.221 → 1.0.0-beta.223
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aglyn/plugins-logic",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.223",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"homepage": "https://aglyn.com",
|
|
6
6
|
"repository": {
|
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
"./package.json": "./package.json"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@aglyn/aglyn": "1.0.0-beta.
|
|
29
|
-
"@aglyn/shared-data-mdi": "1.0.0-beta.
|
|
30
|
-
"@aglyn/shared-ui-jsx": "1.0.0-beta.
|
|
31
|
-
"@aglyn/shared-ui-snackstack": "1.0.0-beta.
|
|
32
|
-
"@aglyn/shared-util-timestamp": "1.0.0-beta.
|
|
33
|
-
"@aglyn/tenant-data-admin": "1.0.0-beta.
|
|
34
|
-
"@aglyn/tenant-feature-instance": "1.0.0-beta.
|
|
28
|
+
"@aglyn/aglyn": "1.0.0-beta.223",
|
|
29
|
+
"@aglyn/shared-data-mdi": "1.0.0-beta.223",
|
|
30
|
+
"@aglyn/shared-ui-jsx": "1.0.0-beta.223",
|
|
31
|
+
"@aglyn/shared-ui-snackstack": "1.0.0-beta.223",
|
|
32
|
+
"@aglyn/shared-util-timestamp": "1.0.0-beta.223",
|
|
33
|
+
"@aglyn/tenant-data-admin": "1.0.0-beta.223",
|
|
34
|
+
"@aglyn/tenant-feature-instance": "1.0.0-beta.223",
|
|
35
35
|
"@swc/helpers": "0.5.23"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
import type {
|
|
17
|
+
import type { InteractionStepBase, SiteInteraction } from '@aglyn/aglyn';
|
|
18
18
|
import type { HostVariable } from '@aglyn/aglyn';
|
|
19
19
|
/**
|
|
20
20
|
* Reference-integrity audit (wave v7): id references (AGL-261) are
|
|
@@ -64,10 +64,33 @@ export interface AuditedVariable extends HostVariable {
|
|
|
64
64
|
workflowId?: string;
|
|
65
65
|
workflowName?: string;
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* A stored automation step, as this audit reads it (AGL-3080): whatever its
|
|
69
|
+
* type, the references a step that acts on a record may carry, each by id and
|
|
70
|
+
* by the name it had when picked. The step vocabulary is the workflows
|
|
71
|
+
* plugin's; the audit reads only these fields of it.
|
|
72
|
+
*/
|
|
73
|
+
export interface AuditedActionStep extends InteractionStepBase {
|
|
74
|
+
workflowId?: string;
|
|
75
|
+
workflowName?: string;
|
|
76
|
+
datasetId?: string;
|
|
77
|
+
datasetName?: string;
|
|
78
|
+
listId?: string;
|
|
79
|
+
listName?: string;
|
|
80
|
+
campaignId?: string;
|
|
81
|
+
campaignName?: string;
|
|
82
|
+
overlayId?: string;
|
|
83
|
+
overlayName?: string;
|
|
84
|
+
webhookId?: string;
|
|
85
|
+
webhookName?: string;
|
|
86
|
+
screenId?: string;
|
|
87
|
+
}
|
|
88
|
+
/** A stored automation, as this audit reads it. */
|
|
89
|
+
export interface AuditedAction extends SiteInteraction<AuditedActionStep> {
|
|
90
|
+
$id: string;
|
|
91
|
+
}
|
|
67
92
|
export interface ReferenceAuditInput {
|
|
68
|
-
actions?:
|
|
69
|
-
$id: string;
|
|
70
|
-
}>;
|
|
93
|
+
actions?: AuditedAction[];
|
|
71
94
|
workflows?: AuditedWorkflow[];
|
|
72
95
|
variables?: AuditedVariable[];
|
|
73
96
|
/** Screen node maps to scan for entity/screen-link references. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/model/reference-audit.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 { HostAction } from '@aglyn/aglyn'\nimport type { HostVariable } from '@aglyn/aglyn'\n\n/**\n * Reference-integrity audit (wave v7): id references (AGL-261) are\n * rename-safe but not delete-safe — deleting a workflow leaves actions\n * pointing at nothing, and the executors fail silently at run time.\n * This pure audit cross-checks every reference an automation, workflow,\n * or computed variable holds against the ids/names that still exist,\n * so the console can surface broken wiring before a visitor hits it.\n */\nexport interface ReferenceIssue {\n /** What holds the broken reference. */\n source: 'action' | 'workflow' | 'variable' | 'screen'\n sourceId: string\n /** Display name of the holder. */\n sourceName: string\n /** What the reference points at (\"workflow\", \"dataset\", …). */\n refType: string\n /** The dangling id or name as stored. */\n missing: string\n}\n\n/** A screen's composed nodes, for canvas-reference auditing (AGL-345). */\nexport interface ScreenAuditEntry {\n $id: string\n name?: string\n nodes: Record<string, { props?: Record<string, unknown> } | undefined>\n}\n\n/**\n * A stored workflow, as far as the audit reads one: its name and the function\n * each step calls, by id and by the name it had when the step was written.\n */\nexport interface AuditedWorkflow {\n $id: string\n name?: string\n steps?: Array<{ functionId?: string; functionName?: string }>\n}\n\n/**\n * A site variable as the audit reads one: computed variables also carry the\n * workflow that computes them, by id and by the name it had when picked.\n */\nexport interface AuditedVariable extends HostVariable {\n $id: string\n workflowId?: string\n workflowName?: string\n}\n\nexport interface ReferenceAuditInput {\n actions?: Array<HostAction & { $id: string }>\n workflows?: AuditedWorkflow[]\n variables?: AuditedVariable[]\n /** Screen node maps to scan for entity/screen-link references. */\n screens?: ScreenAuditEntry[]\n /** Known-good targets: doc ids AND display names both resolve. */\n known: {\n workflows?: Set<string>\n functions?: Set<string>\n datasets?: Set<string>\n lists?: Set<string>\n campaigns?: Set<string>\n overlays?: Set<string>\n webhooks?: Set<string>\n /** New reference kinds (AGL-345). */\n screens?: Set<string>\n products?: Set<string>\n collections?: Set<string>\n categories?: Set<string>\n }\n}\n\nconst resolves = (\n known: Set<string> | undefined,\n id?: string,\n name?: string,\n): boolean => {\n const cleanId = id?.trim()\n const cleanName = name?.trim()\n if (!cleanId && !cleanName) return true // Nothing referenced.\n if (!known) return true // Target kind not loaded — don't cry wolf.\n return Boolean(\n (cleanId && known.has(cleanId)) || (cleanName && known.has(cleanName)),\n )\n}\n\nexport function auditHostReferences(\n input: ReferenceAuditInput,\n): ReferenceIssue[] {\n const issues: ReferenceIssue[] = []\n const { known } = input\n\n for (const action of input.actions ?? []) {\n const push = (refType: string, missing: string) =>\n issues.push({\n source: 'action',\n sourceId: action.$id,\n sourceName: action.name ?? action.$id,\n refType,\n missing,\n })\n for (const step of action.steps ?? []) {\n if (step.type === 'runWorkflow') {\n if (!resolves(known.workflows, step.workflowId, step.workflowName)) {\n push('workflow', step.workflowId || step.workflowName || '')\n }\n } else if (\n step.type === 'datasetAppend' ||\n step.type === 'updateDataset'\n ) {\n if (!resolves(known.datasets, step.datasetId, step.datasetName)) {\n push('dataset', step.datasetId || step.datasetName || '')\n }\n } else if (step.type === 'enrollList') {\n if (!resolves(known.lists, step.listId, step.listName)) {\n push('list', step.listId || step.listName || '')\n }\n } else if (step.type === 'assignCampaign') {\n if (!resolves(known.campaigns, step.campaignId, step.campaignName)) {\n push('campaign', step.campaignId || step.campaignName || '')\n }\n } else if (step.type === 'showOverlay') {\n if (!resolves(known.overlays, step.overlayId, step.overlayName)) {\n push('overlay', step.overlayId || step.overlayName || '')\n }\n } else if (step.type === 'webhookPost') {\n if (!resolves(known.webhooks, step.webhookId, step.webhookName)) {\n push('webhook', step.webhookId || step.webhookName || '')\n }\n } else if (step.type === 'redirect') {\n // Screen-id redirects (AGL-339) go stale when the screen is\n // deleted/unpublished.\n if (!resolves(known.screens, (step as any).screenId)) {\n push('screen', (step as any).screenId || '')\n }\n }\n }\n }\n\n for (const workflow of input.workflows ?? []) {\n for (const step of workflow.steps ?? []) {\n if (!resolves(known.functions, step.functionId, step.functionName)) {\n issues.push({\n source: 'workflow',\n sourceId: workflow.$id,\n sourceName: workflow.name ?? workflow.$id,\n refType: 'function',\n missing: step.functionId || step.functionName || '',\n })\n }\n }\n }\n\n for (const variable of input.variables ?? []) {\n if (!resolves(known.workflows, variable.workflowId, variable.workflowName)) {\n issues.push({\n source: 'variable',\n sourceId: variable.$id,\n sourceName: variable.name ?? variable.$id,\n refType: 'workflow',\n missing: variable.workflowId || variable.workflowName || '',\n })\n }\n }\n\n // Canvas node references (AGL-345): screen links, commerce entities,\n // and repeat datasets persisted in component props.\n const NODE_PROP_TARGETS: Array<{\n prop: string\n refType: string\n known: Set<string> | undefined\n }> = [\n { prop: 'screenId', refType: 'screen', known: known.screens },\n { prop: 'productId', refType: 'product', known: known.products },\n { prop: 'collectionId', refType: 'collection', known: known.collections },\n { prop: 'categoryId', refType: 'category', known: known.categories },\n { prop: 'repeatDataset', refType: 'dataset', known: known.datasets },\n ]\n for (const screen of input.screens ?? []) {\n for (const node of Object.values(screen.nodes ?? {})) {\n const props = node?.props ?? {}\n for (const target of NODE_PROP_TARGETS) {\n const value = props[target.prop]\n if (typeof value !== 'string' || !value.trim()) continue\n if (!resolves(target.known, value)) {\n issues.push({\n source: 'screen',\n sourceId: screen.$id,\n sourceName: screen.name ?? screen.$id,\n refType: target.refType,\n missing: value,\n })\n }\n }\n }\n }\n\n return issues\n}\n"],"names":["resolves","known","id","name","cleanId","trim","cleanName","Boolean","has","auditHostReferences","input","issues","action","actions","push","refType","missing","source","sourceId","$id","sourceName","step","steps","type","workflows","workflowId","workflowName","datasets","datasetId","datasetName","lists","listId","listName","campaigns","campaignId","campaignName","overlays","overlayId","overlayName","webhooks","webhookId","webhookName","screens","screenId","workflow","functions","functionId","functionName","variable","variables","NODE_PROP_TARGETS","prop","products","collections","categories","screen","node","Object","values","nodes","props","target","value"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/model/reference-audit.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 { InteractionStepBase, SiteInteraction } from '@aglyn/aglyn'\nimport type { HostVariable } from '@aglyn/aglyn'\n\n/**\n * Reference-integrity audit (wave v7): id references (AGL-261) are\n * rename-safe but not delete-safe — deleting a workflow leaves actions\n * pointing at nothing, and the executors fail silently at run time.\n * This pure audit cross-checks every reference an automation, workflow,\n * or computed variable holds against the ids/names that still exist,\n * so the console can surface broken wiring before a visitor hits it.\n */\nexport interface ReferenceIssue {\n /** What holds the broken reference. */\n source: 'action' | 'workflow' | 'variable' | 'screen'\n sourceId: string\n /** Display name of the holder. */\n sourceName: string\n /** What the reference points at (\"workflow\", \"dataset\", …). */\n refType: string\n /** The dangling id or name as stored. */\n missing: string\n}\n\n/** A screen's composed nodes, for canvas-reference auditing (AGL-345). */\nexport interface ScreenAuditEntry {\n $id: string\n name?: string\n nodes: Record<string, { props?: Record<string, unknown> } | undefined>\n}\n\n/**\n * A stored workflow, as far as the audit reads one: its name and the function\n * each step calls, by id and by the name it had when the step was written.\n */\nexport interface AuditedWorkflow {\n $id: string\n name?: string\n steps?: Array<{ functionId?: string; functionName?: string }>\n}\n\n/**\n * A site variable as the audit reads one: computed variables also carry the\n * workflow that computes them, by id and by the name it had when picked.\n */\nexport interface AuditedVariable extends HostVariable {\n $id: string\n workflowId?: string\n workflowName?: string\n}\n\n/**\n * A stored automation step, as this audit reads it (AGL-3080): whatever its\n * type, the references a step that acts on a record may carry, each by id and\n * by the name it had when picked. The step vocabulary is the workflows\n * plugin's; the audit reads only these fields of it.\n */\nexport interface AuditedActionStep extends InteractionStepBase {\n workflowId?: string\n workflowName?: string\n datasetId?: string\n datasetName?: string\n listId?: string\n listName?: string\n campaignId?: string\n campaignName?: string\n overlayId?: string\n overlayName?: string\n webhookId?: string\n webhookName?: string\n screenId?: string\n}\n\n/** A stored automation, as this audit reads it. */\nexport interface AuditedAction extends SiteInteraction<AuditedActionStep> {\n $id: string\n}\n\nexport interface ReferenceAuditInput {\n actions?: AuditedAction[]\n workflows?: AuditedWorkflow[]\n variables?: AuditedVariable[]\n /** Screen node maps to scan for entity/screen-link references. */\n screens?: ScreenAuditEntry[]\n /** Known-good targets: doc ids AND display names both resolve. */\n known: {\n workflows?: Set<string>\n functions?: Set<string>\n datasets?: Set<string>\n lists?: Set<string>\n campaigns?: Set<string>\n overlays?: Set<string>\n webhooks?: Set<string>\n /** New reference kinds (AGL-345). */\n screens?: Set<string>\n products?: Set<string>\n collections?: Set<string>\n categories?: Set<string>\n }\n}\n\nconst resolves = (\n known: Set<string> | undefined,\n id?: string,\n name?: string,\n): boolean => {\n const cleanId = id?.trim()\n const cleanName = name?.trim()\n if (!cleanId && !cleanName) return true // Nothing referenced.\n if (!known) return true // Target kind not loaded — don't cry wolf.\n return Boolean(\n (cleanId && known.has(cleanId)) || (cleanName && known.has(cleanName)),\n )\n}\n\nexport function auditHostReferences(\n input: ReferenceAuditInput,\n): ReferenceIssue[] {\n const issues: ReferenceIssue[] = []\n const { known } = input\n\n for (const action of input.actions ?? []) {\n const push = (refType: string, missing: string) =>\n issues.push({\n source: 'action',\n sourceId: action.$id,\n sourceName: action.name ?? action.$id,\n refType,\n missing,\n })\n for (const step of action.steps ?? []) {\n if (step.type === 'runWorkflow') {\n if (!resolves(known.workflows, step.workflowId, step.workflowName)) {\n push('workflow', step.workflowId || step.workflowName || '')\n }\n } else if (\n step.type === 'datasetAppend' ||\n step.type === 'updateDataset'\n ) {\n if (!resolves(known.datasets, step.datasetId, step.datasetName)) {\n push('dataset', step.datasetId || step.datasetName || '')\n }\n } else if (step.type === 'enrollList') {\n if (!resolves(known.lists, step.listId, step.listName)) {\n push('list', step.listId || step.listName || '')\n }\n } else if (step.type === 'assignCampaign') {\n if (!resolves(known.campaigns, step.campaignId, step.campaignName)) {\n push('campaign', step.campaignId || step.campaignName || '')\n }\n } else if (step.type === 'showOverlay') {\n if (!resolves(known.overlays, step.overlayId, step.overlayName)) {\n push('overlay', step.overlayId || step.overlayName || '')\n }\n } else if (step.type === 'webhookPost') {\n if (!resolves(known.webhooks, step.webhookId, step.webhookName)) {\n push('webhook', step.webhookId || step.webhookName || '')\n }\n } else if (step.type === 'redirect') {\n // Screen-id redirects (AGL-339) go stale when the screen is\n // deleted/unpublished.\n if (!resolves(known.screens, step.screenId)) {\n push('screen', step.screenId || '')\n }\n }\n }\n }\n\n for (const workflow of input.workflows ?? []) {\n for (const step of workflow.steps ?? []) {\n if (!resolves(known.functions, step.functionId, step.functionName)) {\n issues.push({\n source: 'workflow',\n sourceId: workflow.$id,\n sourceName: workflow.name ?? workflow.$id,\n refType: 'function',\n missing: step.functionId || step.functionName || '',\n })\n }\n }\n }\n\n for (const variable of input.variables ?? []) {\n if (!resolves(known.workflows, variable.workflowId, variable.workflowName)) {\n issues.push({\n source: 'variable',\n sourceId: variable.$id,\n sourceName: variable.name ?? variable.$id,\n refType: 'workflow',\n missing: variable.workflowId || variable.workflowName || '',\n })\n }\n }\n\n // Canvas node references (AGL-345): screen links, commerce entities,\n // and repeat datasets persisted in component props.\n const NODE_PROP_TARGETS: Array<{\n prop: string\n refType: string\n known: Set<string> | undefined\n }> = [\n { prop: 'screenId', refType: 'screen', known: known.screens },\n { prop: 'productId', refType: 'product', known: known.products },\n { prop: 'collectionId', refType: 'collection', known: known.collections },\n { prop: 'categoryId', refType: 'category', known: known.categories },\n { prop: 'repeatDataset', refType: 'dataset', known: known.datasets },\n ]\n for (const screen of input.screens ?? []) {\n for (const node of Object.values(screen.nodes ?? {})) {\n const props = node?.props ?? {}\n for (const target of NODE_PROP_TARGETS) {\n const value = props[target.prop]\n if (typeof value !== 'string' || !value.trim()) continue\n if (!resolves(target.known, value)) {\n issues.push({\n source: 'screen',\n sourceId: screen.$id,\n sourceName: screen.name ?? screen.$id,\n refType: target.refType,\n missing: value,\n })\n }\n }\n }\n }\n\n return issues\n}\n"],"names":["resolves","known","id","name","cleanId","trim","cleanName","Boolean","has","auditHostReferences","input","issues","action","actions","push","refType","missing","source","sourceId","$id","sourceName","step","steps","type","workflows","workflowId","workflowName","datasets","datasetId","datasetName","lists","listId","listName","campaigns","campaignId","campaignName","overlays","overlayId","overlayName","webhooks","webhookId","webhookName","screens","screenId","workflow","functions","functionId","functionName","variable","variables","NODE_PROP_TARGETS","prop","products","collections","categories","screen","node","Object","values","nodes","props","target","value"],"mappings":"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"}
|
|
@@ -13,11 +13,19 @@
|
|
|
13
13
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
|
-
*/ import {
|
|
17
|
-
import { scopeTokensForHost } from "@aglyn/aglyn/app-utils/scope-tokens";
|
|
16
|
+
*/ import { scopeTokensForHost } from "@aglyn/aglyn/app-utils/scope-tokens";
|
|
18
17
|
import { registerPluginRecordListSource } from "@aglyn/aglyn/plugin-manager/plugin-record-lists";
|
|
19
18
|
import { unregisterPluginServices } from "@aglyn/aglyn/plugin-manager/plugin-services";
|
|
20
19
|
import { collection, documentId, limit, orderBy, query, where } from "firebase/firestore";
|
|
20
|
+
/** A dataset's name as the Data page shows it: its display name, else its legacy name. */ function datasetName(data) {
|
|
21
|
+
for (const candidate of [
|
|
22
|
+
data['displayName'],
|
|
23
|
+
data['name']
|
|
24
|
+
]){
|
|
25
|
+
if (typeof candidate === 'string' && candidate.trim()) return candidate.trim();
|
|
26
|
+
}
|
|
27
|
+
return '';
|
|
28
|
+
}
|
|
21
29
|
/**
|
|
22
30
|
* The `dataset` list source the plugin that keeps the workspace's datasets
|
|
23
31
|
* publishes (AGL-3080), stood in for this plugin's specs — this plugin may
|
|
@@ -37,7 +45,7 @@ import { collection, documentId, limit, orderBy, query, where } from "firebase/f
|
|
|
37
45
|
if (!data || data['deletedAt'] != null) return null;
|
|
38
46
|
return {
|
|
39
47
|
id,
|
|
40
|
-
name:
|
|
48
|
+
name: datasetName(data) || id,
|
|
41
49
|
facts: {
|
|
42
50
|
fields: [],
|
|
43
51
|
visibleTo: Array.isArray(data['visibleTo']) ? data['visibleTo'] : []
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/testing/stand-in-dataset-list.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 {
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/testing/stand-in-dataset-list.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 { scopeTokensForHost } from '@aglyn/aglyn/app-utils/scope-tokens'\nimport { registerPluginRecordListSource } from '@aglyn/aglyn/plugin-manager/plugin-record-lists'\nimport { unregisterPluginServices } from '@aglyn/aglyn/plugin-manager/plugin-services'\nimport { collection, documentId, limit, orderBy, query, where } from 'firebase/firestore'\n\n/** A dataset's name as the Data page shows it: its display name, else its legacy name. */\nfunction datasetName(data: Readonly<Record<string, unknown>>): string {\n for (const candidate of [data['displayName'], data['name']]) {\n if (typeof candidate === 'string' && candidate.trim()) return candidate.trim()\n }\n return ''\n}\n\n/**\n * The `dataset` list source the plugin that keeps the workspace's datasets\n * publishes (AGL-3080), stood in for this plugin's specs — this plugin may\n * not load the data plugin. It builds the query that plugin's\n * `dataset-record-list.ts` builds (a site's answer narrowed by its scope\n * tokens, ordered by document id) from whatever `firebase/firestore` the spec\n * stages, and reads a row as a live dataset named as the Data page names it.\n * What the data plugin itself answers is held in its own spec.\n */\nexport function standInDatasetList(): void {\n registerPluginRecordListSource(\n 'dataset',\n {\n query(firestore, request) {\n if (!request.orgId) return null\n const datasets = collection(firestore, 'orgs', request.orgId, 'datasets')\n return request.hostId\n ? query(\n datasets,\n where('visibleTo', 'array-contains-any', scopeTokensForHost(request.hostId)),\n orderBy(documentId()),\n limit(request.limit),\n )\n : query(datasets, orderBy(documentId()), limit(request.limit))\n },\n record(id, data) {\n if (!data || data['deletedAt'] != null) return null\n return {\n id,\n name: datasetName(data) || id,\n facts: { fields: [], visibleTo: Array.isArray(data['visibleTo']) ? data['visibleTo'] : [] },\n }\n },\n },\n { pluginId: 'data' },\n )\n}\n\n/** Forgets it, so a spec can ask what happens where no plugin keeps datasets. */\nexport function removeStandInDatasetList(): void {\n unregisterPluginServices('data')\n}\n"],"names":["scopeTokensForHost","registerPluginRecordListSource","unregisterPluginServices","collection","documentId","limit","orderBy","query","where","datasetName","data","candidate","trim","standInDatasetList","firestore","request","orgId","datasets","hostId","record","id","name","facts","fields","visibleTo","Array","isArray","pluginId","removeStandInDatasetList"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,kBAAkB,QAAQ,sCAAqC;AACxE,SAASC,8BAA8B,QAAQ,kDAAiD;AAChG,SAASC,wBAAwB,QAAQ,8CAA6C;AACtF,SAASC,UAAU,EAAEC,UAAU,EAAEC,KAAK,EAAEC,OAAO,EAAEC,KAAK,EAAEC,KAAK,QAAQ,qBAAoB;AAEzF,wFAAwF,GACxF,SAASC,YAAYC,IAAuC;IAC1D,KAAK,MAAMC,aAAa;QAACD,IAAI,CAAC,cAAc;QAAEA,IAAI,CAAC,OAAO;KAAC,CAAE;QAC3D,IAAI,OAAOC,cAAc,YAAYA,UAAUC,IAAI,IAAI,OAAOD,UAAUC,IAAI;IAC9E;IACA,OAAO;AACT;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASC;IACdZ,+BACE,WACA;QACEM,OAAMO,SAAS,EAAEC,OAAO;YACtB,IAAI,CAACA,QAAQC,KAAK,EAAE,OAAO;YAC3B,MAAMC,WAAWd,WAAWW,WAAW,QAAQC,QAAQC,KAAK,EAAE;YAC9D,OAAOD,QAAQG,MAAM,GACjBX,MACEU,UACAT,MAAM,aAAa,sBAAsBR,mBAAmBe,QAAQG,MAAM,IAC1EZ,QAAQF,eACRC,MAAMU,QAAQV,KAAK,KAErBE,MAAMU,UAAUX,QAAQF,eAAeC,MAAMU,QAAQV,KAAK;QAChE;QACAc,QAAOC,EAAE,EAAEV,IAAI;YACb,IAAI,CAACA,QAAQA,IAAI,CAAC,YAAY,IAAI,MAAM,OAAO;YAC/C,OAAO;gBACLU;gBACAC,MAAMZ,YAAYC,SAASU;gBAC3BE,OAAO;oBAAEC,QAAQ,EAAE;oBAAEC,WAAWC,MAAMC,OAAO,CAAChB,IAAI,CAAC,YAAY,IAAIA,IAAI,CAAC,YAAY,GAAG,EAAE;gBAAC;YAC5F;QACF;IACF,GACA;QAAEiB,UAAU;IAAO;AAEvB;AAEA,+EAA+E,GAC/E,OAAO,SAASC;IACd1B,yBAAyB;AAC3B"}
|