@aglyn/aglyn 1.0.0-beta.270 → 1.0.0-beta.272
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 +11 -11
- package/src/lib/app-utils/account-preferences.d.ts +50 -0
- package/src/lib/app-utils/account-preferences.js +96 -0
- package/src/lib/app-utils/account-preferences.js.map +1 -1
- package/src/lib/app-utils/activity-labels.js +2 -0
- package/src/lib/app-utils/activity-labels.js.map +1 -1
- package/src/lib/app-utils/analytics-events.d.ts +16 -2
- package/src/lib/app-utils/analytics-events.js +2 -0
- package/src/lib/app-utils/analytics-events.js.map +1 -1
- package/src/lib/app-utils/append-only-history.d.ts +94 -0
- package/src/lib/app-utils/append-only-history.js +73 -0
- package/src/lib/app-utils/append-only-history.js.map +1 -0
- package/src/lib/app-utils/bundle-intent.d.ts +186 -0
- package/src/lib/app-utils/bundle-intent.js +386 -0
- package/src/lib/app-utils/bundle-intent.js.map +1 -0
- package/src/lib/app-utils/client-build.d.ts +207 -0
- package/src/lib/app-utils/client-build.js +237 -0
- package/src/lib/app-utils/client-build.js.map +1 -0
- package/src/lib/app-utils/console-routes.d.ts +4 -0
- package/src/lib/app-utils/console-routes.js +2 -0
- package/src/lib/app-utils/console-routes.js.map +1 -1
- package/src/lib/app-utils/docs-help-sections.generated.js +13 -6
- package/src/lib/app-utils/docs-help-sections.generated.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +11 -5
- package/src/lib/app-utils/docs-help.generated.js +31 -2
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +105 -35
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/margin-utilization.js +6 -4
- package/src/lib/app-utils/margin-utilization.js.map +1 -1
- package/src/lib/app-utils/media-filter.d.ts +26 -0
- package/src/lib/app-utils/media-filter.js +32 -0
- package/src/lib/app-utils/media-filter.js.map +1 -1
- package/src/lib/app-utils/onboarding-deep-link.d.ts +36 -2
- package/src/lib/app-utils/onboarding-deep-link.js +48 -5
- package/src/lib/app-utils/onboarding-deep-link.js.map +1 -1
- package/src/lib/app-utils/operator-alerts.js +21 -0
- package/src/lib/app-utils/operator-alerts.js.map +1 -1
- package/src/lib/app-utils/owner-approval-record.d.ts +102 -0
- package/src/lib/app-utils/owner-approval-record.js +148 -0
- package/src/lib/app-utils/owner-approval-record.js.map +1 -0
- package/src/lib/app-utils/plan-card-meters.d.ts +96 -0
- package/src/lib/app-utils/plan-card-meters.js +197 -0
- package/src/lib/app-utils/plan-card-meters.js.map +1 -0
- package/src/lib/app-utils/plan-entitlements.d.ts +183 -67
- package/src/lib/app-utils/plan-entitlements.js +213 -58
- package/src/lib/app-utils/plan-entitlements.js.map +1 -1
- package/src/lib/app-utils/release-flags.d.ts +1 -1
- package/src/lib/app-utils/release-flags.js +22 -0
- package/src/lib/app-utils/release-flags.js.map +1 -1
- package/src/lib/app-utils/server.d.ts +4 -0
- package/src/lib/app-utils/server.js +7 -0
- package/src/lib/app-utils/server.js.map +1 -1
- package/src/lib/app-utils/site-care-project.d.ts +227 -0
- package/src/lib/app-utils/site-care-project.js +423 -0
- package/src/lib/app-utils/site-care-project.js.map +1 -0
- package/src/lib/app-utils/site-care.d.ts +291 -0
- package/src/lib/app-utils/site-care.js +310 -0
- package/src/lib/app-utils/site-care.js.map +1 -0
- package/src/lib/app-utils/upgrade-proposal.d.ts +29 -4
- package/src/lib/app-utils/upgrade-proposal.js +60 -9
- package/src/lib/app-utils/upgrade-proposal.js.map +1 -1
- package/src/lib/foundation/definitions/org-billing.types.d.ts +40 -10
- package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
- package/src/lib/foundation/definitions/organization.types.d.ts +3 -1
- package/src/lib/foundation/definitions/organization.types.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +20 -0
- package/src/lib/foundation/definitions/platform.types.js.map +1 -1
- package/src/lib/foundation/index.d.ts +1 -1
- package/src/lib/foundation/index.js.map +1 -1
- package/src/lib/plugin-manager/feature-plugins.d.ts +48 -0
- package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
- package/src/lib/plugin-manager/first-party-plugins.generated.js +16 -0
- package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
- package/src/lib/plugin-manager/plugin-ai-capabilities.d.ts +19 -0
- package/src/lib/plugin-manager/plugin-ai-capabilities.js.map +1 -1
- package/src/lib/plugin-manager/plugin-domain-search.d.ts +81 -0
- package/src/lib/plugin-manager/plugin-domain-search.js +63 -0
- package/src/lib/plugin-manager/plugin-domain-search.js.map +1 -0
- package/src/lib/plugin-manager/plugin-entitlements.d.ts +23 -5
- package/src/lib/plugin-manager/plugin-entitlements.js +10 -0
- package/src/lib/plugin-manager/plugin-entitlements.js.map +1 -1
- package/src/lib/plugin-manager/plugin-media-ingest.d.ts +18 -1
- package/src/lib/plugin-manager/plugin-media-ingest.js.map +1 -1
- package/src/lib/plugin-manager/plugin-site-resources.d.ts +74 -0
- package/src/lib/plugin-manager/plugin-site-resources.js +135 -0
- package/src/lib/plugin-manager/plugin-site-resources.js.map +1 -0
- package/src/lib/plugin-manager/purchase-gate-preclearance.d.ts +61 -0
- package/src/lib/plugin-manager/purchase-gate-preclearance.js +102 -0
- package/src/lib/plugin-manager/purchase-gate-preclearance.js.map +1 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
var _globalScope_ERASERS_KEY;
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ /**
|
|
18
|
+
* A PLUGIN'S SHARE OF DELETING A SITE (AGL-4003).
|
|
19
|
+
*
|
|
20
|
+
* Deleting a site (`eraseHost`) destroys what the platform holds for it: its
|
|
21
|
+
* document tree, its Storage, its routing, and the organization documents a
|
|
22
|
+
* plugin declares as the site's (`orgCollections` with a `siteField`). Some
|
|
23
|
+
* plugin resources belong to the ORGANIZATION and are shared with sites by a
|
|
24
|
+
* scope list instead — a dataset shared with one site, or with several. Which
|
|
25
|
+
* of those are the site's own, and what becomes of the rest, is the plugin's
|
|
26
|
+
* to say, so the plugin registers a site-resource eraser here:
|
|
27
|
+
*
|
|
28
|
+
* - `preview` lists what deleting the site would take — the resources shared
|
|
29
|
+
* with this site alone, each with how many items it holds — and how many it
|
|
30
|
+
* shares with other sites, which stay. The Delete site card shows it before
|
|
31
|
+
* anyone confirms, so it must change nothing.
|
|
32
|
+
* - `erase` erases the resources shared with this site alone, items and all,
|
|
33
|
+
* and takes the site off the sharing of the ones it shares with others. It
|
|
34
|
+
* answers how many it erased.
|
|
35
|
+
*
|
|
36
|
+
* Erasers run in registration order and are ISOLATED, like every trailing
|
|
37
|
+
* cleanup of a site delete: a throw is logged against its plugin and does not
|
|
38
|
+
* stop the next one or the delete. A preview that throws is reported as
|
|
39
|
+
* `null` for its plugin, so the card can say the list is incomplete rather
|
|
40
|
+
* than show an empty one.
|
|
41
|
+
*
|
|
42
|
+
* Registered from a plugin's `serverDeclarations`, so the eraser is in place
|
|
43
|
+
* in every server process that can delete a site.
|
|
44
|
+
*/ import { getRegisteringPluginId } from "../app-utils/registering-plugin.js";
|
|
45
|
+
import { runPluginDeclarationsRepair } from "./plugin-declarations-repair.js";
|
|
46
|
+
/**
|
|
47
|
+
* One list per process, on `globalThis` (AGL-3464): the app registers its
|
|
48
|
+
* plugins' declarations from `instrumentation.ts`, which Next compiles apart
|
|
49
|
+
* from the route that deletes a site, and a module-scoped list is filled in
|
|
50
|
+
* one copy and read empty in the other.
|
|
51
|
+
*/ const ERASERS_KEY = Symbol.for('@aglyn/aglyn:plugin-site-resource-erasers');
|
|
52
|
+
const globalScope = globalThis;
|
|
53
|
+
const registrations = (_globalScope_ERASERS_KEY = globalScope[ERASERS_KEY]) != null ? _globalScope_ERASERS_KEY : globalScope[ERASERS_KEY] = [];
|
|
54
|
+
/**
|
|
55
|
+
* Registers a plugin's site-resource eraser. Owner = the loader's marker
|
|
56
|
+
* inside a register fn, else `options.pluginId`; an eraser with neither
|
|
57
|
+
* throws. One per plugin: registering again replaces the plugin's earlier
|
|
58
|
+
* eraser in place, so a module evaluated twice does not erase twice.
|
|
59
|
+
*/ export function registerPluginSiteResourceEraser(eraser, options) {
|
|
60
|
+
var _ref, _getRegisteringPluginId;
|
|
61
|
+
const pluginId = ((_ref = (_getRegisteringPluginId = getRegisteringPluginId()) != null ? _getRegisteringPluginId : options == null ? void 0 : options.pluginId) != null ? _ref : '').trim();
|
|
62
|
+
if (!pluginId) {
|
|
63
|
+
throw new Error('a plugin site-resource eraser was registered with no owner: pass ' + '{ pluginId } when registering outside a plugin register fn');
|
|
64
|
+
}
|
|
65
|
+
if (typeof (eraser == null ? void 0 : eraser.preview) !== 'function' || typeof (eraser == null ? void 0 : eraser.erase) !== 'function') {
|
|
66
|
+
throw new Error('a site-resource eraser needs a preview and an erase function');
|
|
67
|
+
}
|
|
68
|
+
const index = registrations.findIndex((entry)=>entry.pluginId === pluginId);
|
|
69
|
+
if (index >= 0) registrations[index] = {
|
|
70
|
+
pluginId,
|
|
71
|
+
eraser
|
|
72
|
+
};
|
|
73
|
+
else registrations.push({
|
|
74
|
+
pluginId,
|
|
75
|
+
eraser
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The erasers in place, after running the app's boot step once when none is:
|
|
80
|
+
* a boot whose declarations failed must not read as a workspace with nothing
|
|
81
|
+
* shared with the site.
|
|
82
|
+
*/ async function registered() {
|
|
83
|
+
if (!registrations.length) {
|
|
84
|
+
await runPluginDeclarationsRepair().catch((error)=>{
|
|
85
|
+
console.error('[plugins] the declarations repair failed before a site delete', error);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return [
|
|
89
|
+
...registrations
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Every plugin's preview, in registration order. Never throws: a preview that
|
|
94
|
+
* fails is logged and answered as `null` for its plugin.
|
|
95
|
+
*/ export async function previewPluginSiteResources(request) {
|
|
96
|
+
const rows = [];
|
|
97
|
+
for (const { pluginId, eraser } of (await registered())){
|
|
98
|
+
try {
|
|
99
|
+
rows.push({
|
|
100
|
+
pluginId,
|
|
101
|
+
preview: await eraser.preview(request)
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(`[plugins] ${pluginId} could not list what goes with site ${request.hostId}`, error);
|
|
105
|
+
rows.push({
|
|
106
|
+
pluginId,
|
|
107
|
+
preview: null
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return rows;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Runs every eraser, in registration order, and answers how many resources
|
|
115
|
+
* each erased by plugin id, or `null` for one that threw. Never throws.
|
|
116
|
+
*/ export async function erasePluginSiteResources(request) {
|
|
117
|
+
const erased = {};
|
|
118
|
+
for (const { pluginId, eraser } of (await registered())){
|
|
119
|
+
try {
|
|
120
|
+
erased[pluginId] = await eraser.erase(request);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
erased[pluginId] = null;
|
|
123
|
+
console.error(`[plugins] ${pluginId} failed to erase site ${request.hostId}'s resources`, error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return erased;
|
|
127
|
+
}
|
|
128
|
+
/** The plugins with a site-resource eraser, in the order they run. */ export function listPluginSiteResourceErasers() {
|
|
129
|
+
return registrations.map((entry)=>entry.pluginId);
|
|
130
|
+
}
|
|
131
|
+
/** Test seam: forget every eraser. */ export function resetPluginSiteResourceErasersForTests() {
|
|
132
|
+
registrations.length = 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=plugin-site-resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-site-resources.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A PLUGIN'S SHARE OF DELETING A SITE (AGL-4003).\n *\n * Deleting a site (`eraseHost`) destroys what the platform holds for it: its\n * document tree, its Storage, its routing, and the organization documents a\n * plugin declares as the site's (`orgCollections` with a `siteField`). Some\n * plugin resources belong to the ORGANIZATION and are shared with sites by a\n * scope list instead — a dataset shared with one site, or with several. Which\n * of those are the site's own, and what becomes of the rest, is the plugin's\n * to say, so the plugin registers a site-resource eraser here:\n *\n * - `preview` lists what deleting the site would take — the resources shared\n * with this site alone, each with how many items it holds — and how many it\n * shares with other sites, which stay. The Delete site card shows it before\n * anyone confirms, so it must change nothing.\n * - `erase` erases the resources shared with this site alone, items and all,\n * and takes the site off the sharing of the ones it shares with others. It\n * answers how many it erased.\n *\n * Erasers run in registration order and are ISOLATED, like every trailing\n * cleanup of a site delete: a throw is logged against its plugin and does not\n * stop the next one or the delete. A preview that throws is reported as\n * `null` for its plugin, so the card can say the list is incomplete rather\n * than show an empty one.\n *\n * Registered from a plugin's `serverDeclarations`, so the eraser is in place\n * in every server process that can delete a site.\n */\n\nimport { getRegisteringPluginId } from '../app-utils/registering-plugin'\nimport { runPluginDeclarationsRepair } from './plugin-declarations-repair'\n\n/** The site a preview or an erase is about, and the workspace that owns it. */\nexport interface PluginSiteResourceRequest {\n orgId: string\n hostId: string\n}\n\n/** One resource that goes with the site. */\nexport interface PluginSiteResourceGoing {\n id: string\n /** Its name, as the plugin's own page shows it. */\n name: string\n /** How many items it holds; `null` where they could not be counted. */\n items: number | null\n}\n\n/** What deleting the site does to one plugin's resources. */\nexport interface PluginSiteResourcePreview {\n /** What one resource is called, and several: `['dataset', 'datasets']`. */\n noun: readonly [string, string]\n /** What one of its items is called, and several: `['record', 'records']`. */\n itemNoun: readonly [string, string]\n /** Shared with this site alone: erased with every item. */\n going: PluginSiteResourceGoing[]\n /** Shared with this site and others: they stay, and lose this site. */\n staying: number\n}\n\nexport interface PluginSiteResourceEraser {\n /** What deleting the site would take. Reads only. */\n preview(request: PluginSiteResourceRequest): Promise<PluginSiteResourcePreview>\n /** Erases the site's own resources; answers how many it erased. */\n erase(request: PluginSiteResourceRequest): Promise<number>\n}\n\ninterface Registration {\n pluginId: string\n eraser: PluginSiteResourceEraser\n}\n\n/**\n * One list per process, on `globalThis` (AGL-3464): the app registers its\n * plugins' declarations from `instrumentation.ts`, which Next compiles apart\n * from the route that deletes a site, and a module-scoped list is filled in\n * one copy and read empty in the other.\n */\nconst ERASERS_KEY = Symbol.for('@aglyn/aglyn:plugin-site-resource-erasers')\n\nconst globalScope = globalThis as typeof globalThis & {\n [ERASERS_KEY]?: Registration[]\n}\n\nconst registrations: Registration[] =\n globalScope[ERASERS_KEY] ?? (globalScope[ERASERS_KEY] = [])\n\n/**\n * Registers a plugin's site-resource eraser. Owner = the loader's marker\n * inside a register fn, else `options.pluginId`; an eraser with neither\n * throws. One per plugin: registering again replaces the plugin's earlier\n * eraser in place, so a module evaluated twice does not erase twice.\n */\nexport function registerPluginSiteResourceEraser(\n eraser: PluginSiteResourceEraser,\n options?: { pluginId?: string },\n): void {\n const pluginId = (getRegisteringPluginId() ?? options?.pluginId ?? '').trim()\n if (!pluginId) {\n throw new Error(\n 'a plugin site-resource eraser was registered with no owner: pass ' +\n '{ pluginId } when registering outside a plugin register fn',\n )\n }\n if (typeof eraser?.preview !== 'function' || typeof eraser?.erase !== 'function') {\n throw new Error('a site-resource eraser needs a preview and an erase function')\n }\n const index = registrations.findIndex((entry) => entry.pluginId === pluginId)\n if (index >= 0) registrations[index] = { pluginId, eraser }\n else registrations.push({ pluginId, eraser })\n}\n\n/**\n * The erasers in place, after running the app's boot step once when none is:\n * a boot whose declarations failed must not read as a workspace with nothing\n * shared with the site.\n */\nasync function registered(): Promise<Registration[]> {\n if (!registrations.length) {\n await runPluginDeclarationsRepair().catch((error: unknown) => {\n console.error('[plugins] the declarations repair failed before a site delete', error)\n })\n }\n return [...registrations]\n}\n\n/** One plugin's preview, or `null` where its preview failed. */\nexport interface PluginSiteResourcePreviewRow {\n pluginId: string\n preview: PluginSiteResourcePreview | null\n}\n\n/**\n * Every plugin's preview, in registration order. Never throws: a preview that\n * fails is logged and answered as `null` for its plugin.\n */\nexport async function previewPluginSiteResources(\n request: PluginSiteResourceRequest,\n): Promise<PluginSiteResourcePreviewRow[]> {\n const rows: PluginSiteResourcePreviewRow[] = []\n for (const { pluginId, eraser } of await registered()) {\n try {\n rows.push({ pluginId, preview: await eraser.preview(request) })\n } catch (error) {\n console.error(\n `[plugins] ${pluginId} could not list what goes with site ${request.hostId}`,\n error,\n )\n rows.push({ pluginId, preview: null })\n }\n }\n return rows\n}\n\n/**\n * Runs every eraser, in registration order, and answers how many resources\n * each erased by plugin id, or `null` for one that threw. Never throws.\n */\nexport async function erasePluginSiteResources(\n request: PluginSiteResourceRequest,\n): Promise<Record<string, number | null>> {\n const erased: Record<string, number | null> = {}\n for (const { pluginId, eraser } of await registered()) {\n try {\n erased[pluginId] = await eraser.erase(request)\n } catch (error) {\n erased[pluginId] = null\n console.error(`[plugins] ${pluginId} failed to erase site ${request.hostId}'s resources`, error)\n }\n }\n return erased\n}\n\n/** The plugins with a site-resource eraser, in the order they run. */\nexport function listPluginSiteResourceErasers(): string[] {\n return registrations.map((entry) => entry.pluginId)\n}\n\n/** Test seam: forget every eraser. */\nexport function resetPluginSiteResourceErasersForTests(): void {\n registrations.length = 0\n}\n"],"names":["globalScope","getRegisteringPluginId","runPluginDeclarationsRepair","ERASERS_KEY","Symbol","for","globalThis","registrations","registerPluginSiteResourceEraser","eraser","options","pluginId","trim","Error","preview","erase","index","findIndex","entry","push","registered","length","catch","error","console","previewPluginSiteResources","request","rows","hostId","erasePluginSiteResources","erased","listPluginSiteResourceErasers","map","resetPluginSiteResourceErasersForTests"],"mappings":"IAqGEA;AArGF;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GAED,SAASC,sBAAsB,QAAQ,qCAAiC;AACxE,SAASC,2BAA2B,QAAQ,kCAA8B;AAyC1E;;;;;CAKC,GACD,MAAMC,cAAcC,OAAOC,GAAG,CAAC;AAE/B,MAAML,cAAcM;AAIpB,MAAMC,iBACJP,2BAAAA,WAAW,CAACG,YAAY,YAAxBH,2BAA6BA,WAAW,CAACG,YAAY,GAAG,EAAE;AAE5D;;;;;CAKC,GACD,OAAO,SAASK,iCACdC,MAAgC,EAChCC,OAA+B;QAEbT,MAAAA;IAAlB,MAAMU,WAAW,EAACV,QAAAA,0BAAAA,oCAAAA,0BAA4BS,2BAAAA,QAASC,QAAQ,YAA7CV,OAAiD,IAAIW,IAAI;IAC3E,IAAI,CAACD,UAAU;QACb,MAAM,IAAIE,MACR,sEACE;IAEN;IACA,IAAI,QAAOJ,0BAAAA,OAAQK,OAAO,MAAK,cAAc,QAAOL,0BAAAA,OAAQM,KAAK,MAAK,YAAY;QAChF,MAAM,IAAIF,MAAM;IAClB;IACA,MAAMG,QAAQT,cAAcU,SAAS,CAAC,CAACC,QAAUA,MAAMP,QAAQ,KAAKA;IACpE,IAAIK,SAAS,GAAGT,aAAa,CAACS,MAAM,GAAG;QAAEL;QAAUF;IAAO;SACrDF,cAAcY,IAAI,CAAC;QAAER;QAAUF;IAAO;AAC7C;AAEA;;;;CAIC,GACD,eAAeW;IACb,IAAI,CAACb,cAAcc,MAAM,EAAE;QACzB,MAAMnB,8BAA8BoB,KAAK,CAAC,CAACC;YACzCC,QAAQD,KAAK,CAAC,iEAAiEA;QACjF;IACF;IACA,OAAO;WAAIhB;KAAc;AAC3B;AAQA;;;CAGC,GACD,OAAO,eAAekB,2BACpBC,OAAkC;IAElC,MAAMC,OAAuC,EAAE;IAC/C,KAAK,MAAM,EAAEhB,QAAQ,EAAEF,MAAM,EAAE,IAAI,CAAA,MAAMW,YAAW,EAAG;QACrD,IAAI;YACFO,KAAKR,IAAI,CAAC;gBAAER;gBAAUG,SAAS,MAAML,OAAOK,OAAO,CAACY;YAAS;QAC/D,EAAE,OAAOH,OAAO;YACdC,QAAQD,KAAK,CACX,CAAC,UAAU,EAAEZ,SAAS,oCAAoC,EAAEe,QAAQE,MAAM,EAAE,EAC5EL;YAEFI,KAAKR,IAAI,CAAC;gBAAER;gBAAUG,SAAS;YAAK;QACtC;IACF;IACA,OAAOa;AACT;AAEA;;;CAGC,GACD,OAAO,eAAeE,yBACpBH,OAAkC;IAElC,MAAMI,SAAwC,CAAC;IAC/C,KAAK,MAAM,EAAEnB,QAAQ,EAAEF,MAAM,EAAE,IAAI,CAAA,MAAMW,YAAW,EAAG;QACrD,IAAI;YACFU,MAAM,CAACnB,SAAS,GAAG,MAAMF,OAAOM,KAAK,CAACW;QACxC,EAAE,OAAOH,OAAO;YACdO,MAAM,CAACnB,SAAS,GAAG;YACnBa,QAAQD,KAAK,CAAC,CAAC,UAAU,EAAEZ,SAAS,sBAAsB,EAAEe,QAAQE,MAAM,CAAC,YAAY,CAAC,EAAEL;QAC5F;IACF;IACA,OAAOO;AACT;AAEA,oEAAoE,GACpE,OAAO,SAASC;IACd,OAAOxB,cAAcyB,GAAG,CAAC,CAACd,QAAUA,MAAMP,QAAQ;AACpD;AAEA,oCAAoC,GACpC,OAAO,SAASsB;IACd1B,cAAcc,MAAM,GAAG;AACzB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/** The gates a preclearance may waive. One today. */
|
|
18
|
+
export type PurchaseGate = 'domain-payment-history';
|
|
19
|
+
export interface PurchaseGatePreclearanceInput {
|
|
20
|
+
/** The workspace the purchase is for. */
|
|
21
|
+
orgId: string;
|
|
22
|
+
gate: PurchaseGate;
|
|
23
|
+
}
|
|
24
|
+
export interface PurchaseGatePreclearance {
|
|
25
|
+
/**
|
|
26
|
+
* A live, unused waiver for this workspace and gate, or null. Reads only:
|
|
27
|
+
* asking does not spend it.
|
|
28
|
+
*/
|
|
29
|
+
check(input: PurchaseGatePreclearanceInput): Promise<{
|
|
30
|
+
preclearanceId: string;
|
|
31
|
+
} | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Spend the waiver: true exactly once per id, in a transaction that marks it
|
|
34
|
+
* used only if nothing has. False for an id this implementation does not
|
|
35
|
+
* hold, one already spent, or one that expired.
|
|
36
|
+
*/
|
|
37
|
+
consume(preclearanceId: string): Promise<boolean>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A set: more than one surface may mint a waiver (a bundle link today), and
|
|
41
|
+
* the gate asks each in turn.
|
|
42
|
+
*/
|
|
43
|
+
export declare const PURCHASE_GATE_PRECLEARANCE: import("./plugin-services").PluginServiceContract<PurchaseGatePreclearance>;
|
|
44
|
+
/** Installs an implementation. The console registers the bundle links at boot. */
|
|
45
|
+
export declare function registerPurchaseGatePreclearance(impl: PurchaseGatePreclearance, options?: {
|
|
46
|
+
pluginId?: string;
|
|
47
|
+
key?: string;
|
|
48
|
+
}): void;
|
|
49
|
+
/**
|
|
50
|
+
* The first live waiver any implementation holds for the workspace and gate,
|
|
51
|
+
* or null. Never throws; an implementation that throws is skipped and
|
|
52
|
+
* logged, so it can only ever cost a waiver, never grant one.
|
|
53
|
+
*/
|
|
54
|
+
export declare function checkPurchaseGatePreclearance(input: PurchaseGatePreclearanceInput): Promise<{
|
|
55
|
+
preclearanceId: string;
|
|
56
|
+
} | null>;
|
|
57
|
+
/**
|
|
58
|
+
* Spend a waiver. True only when an implementation marked it used just now.
|
|
59
|
+
* Never throws: a failure answers false, which refuses the purchase.
|
|
60
|
+
*/
|
|
61
|
+
export declare function consumePurchaseGatePreclearance(preclearanceId: string): Promise<boolean>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ /**
|
|
18
|
+
* WHO MAY WAIVE A PURCHASE GATE, ONCE (AGL-3955).
|
|
19
|
+
*
|
|
20
|
+
* A plugin that sells something can hold a purchase behind a gate the
|
|
21
|
+
* workspace has to earn: the domains plugin refuses to register a name until
|
|
22
|
+
* the workspace has a paid platform invoice at least 72 hours old. Core owns
|
|
23
|
+
* the one thing that can stand in for that history: a staff member who met
|
|
24
|
+
* the owner in person and minted a single-use bundle link for that one
|
|
25
|
+
* workspace, accountable for it in `adminAudit`.
|
|
26
|
+
*
|
|
27
|
+
* The plugin cannot read core's bundle-link records (a plugin never imports
|
|
28
|
+
* core's storage, and never another plugin), so the waiver is a contract
|
|
29
|
+
* here. The plugin asks `check` while deciding whether the gate refuses, and
|
|
30
|
+
* calls `consume` after it has taken its own hold and before it charges: a
|
|
31
|
+
* `false` from `consume` refuses the purchase, so one preclearance buys
|
|
32
|
+
* exactly one thing.
|
|
33
|
+
*
|
|
34
|
+
* Only the named gate is waived. Every other refusal the plugin makes (a
|
|
35
|
+
* brand lookalike, its per-workspace caps) stands, and an implementation has
|
|
36
|
+
* no say in them.
|
|
37
|
+
*
|
|
38
|
+
* ## FAILS CLOSED
|
|
39
|
+
*
|
|
40
|
+
* {@link checkPurchaseGatePreclearance} answers null on any error and when
|
|
41
|
+
* nothing is registered, and {@link consumePurchaseGatePreclearance} answers
|
|
42
|
+
* false: a waiver that cannot be confirmed is no waiver, and the gate keeps
|
|
43
|
+
* refusing.
|
|
44
|
+
*/ import { definePluginServiceContract, registerPluginService, resolvePluginServices } from "./plugin-services.js";
|
|
45
|
+
/**
|
|
46
|
+
* A set: more than one surface may mint a waiver (a bundle link today), and
|
|
47
|
+
* the gate asks each in turn.
|
|
48
|
+
*/ export const PURCHASE_GATE_PRECLEARANCE = definePluginServiceContract('core.purchase-gate-preclearance', {
|
|
49
|
+
multiple: true
|
|
50
|
+
});
|
|
51
|
+
/** Installs an implementation. The console registers the bundle links at boot. */ export function registerPurchaseGatePreclearance(impl, options) {
|
|
52
|
+
if (typeof (impl == null ? void 0 : impl.check) !== 'function' || typeof (impl == null ? void 0 : impl.consume) !== 'function') {
|
|
53
|
+
throw new Error('a purchase gate preclearance needs check and consume functions');
|
|
54
|
+
}
|
|
55
|
+
registerPluginService(PURCHASE_GATE_PRECLEARANCE, impl, _extends({}, (options == null ? void 0 : options.pluginId) ? {
|
|
56
|
+
pluginId: options.pluginId
|
|
57
|
+
} : {}, (options == null ? void 0 : options.key) ? {
|
|
58
|
+
key: options.key
|
|
59
|
+
} : {}));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The first live waiver any implementation holds for the workspace and gate,
|
|
63
|
+
* or null. Never throws; an implementation that throws is skipped and
|
|
64
|
+
* logged, so it can only ever cost a waiver, never grant one.
|
|
65
|
+
*/ export async function checkPurchaseGatePreclearance(input) {
|
|
66
|
+
var _ref;
|
|
67
|
+
const orgId = String((_ref = input == null ? void 0 : input.orgId) != null ? _ref : '').trim();
|
|
68
|
+
if (!orgId || (input == null ? void 0 : input.gate) !== 'domain-payment-history') return null;
|
|
69
|
+
for (const registration of resolvePluginServices(PURCHASE_GATE_PRECLEARANCE)){
|
|
70
|
+
try {
|
|
71
|
+
var _ref1;
|
|
72
|
+
const found = await registration.impl.check({
|
|
73
|
+
orgId,
|
|
74
|
+
gate: input.gate
|
|
75
|
+
});
|
|
76
|
+
const preclearanceId = String((_ref1 = found == null ? void 0 : found.preclearanceId) != null ? _ref1 : '').trim();
|
|
77
|
+
if (preclearanceId) return {
|
|
78
|
+
preclearanceId
|
|
79
|
+
};
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(`[purchase-gate-preclearance] check failed in "${registration.pluginId}"`, error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Spend a waiver. True only when an implementation marked it used just now.
|
|
88
|
+
* Never throws: a failure answers false, which refuses the purchase.
|
|
89
|
+
*/ export async function consumePurchaseGatePreclearance(preclearanceId) {
|
|
90
|
+
const id = String(preclearanceId != null ? preclearanceId : '').trim();
|
|
91
|
+
if (!id) return false;
|
|
92
|
+
for (const registration of resolvePluginServices(PURCHASE_GATE_PRECLEARANCE)){
|
|
93
|
+
try {
|
|
94
|
+
if (await registration.impl.consume(id) === true) return true;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error(`[purchase-gate-preclearance] consume failed in "${registration.pluginId}"`, error);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
//# sourceMappingURL=purchase-gate-preclearance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/purchase-gate-preclearance.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * WHO MAY WAIVE A PURCHASE GATE, ONCE (AGL-3955).\n *\n * A plugin that sells something can hold a purchase behind a gate the\n * workspace has to earn: the domains plugin refuses to register a name until\n * the workspace has a paid platform invoice at least 72 hours old. Core owns\n * the one thing that can stand in for that history: a staff member who met\n * the owner in person and minted a single-use bundle link for that one\n * workspace, accountable for it in `adminAudit`.\n *\n * The plugin cannot read core's bundle-link records (a plugin never imports\n * core's storage, and never another plugin), so the waiver is a contract\n * here. The plugin asks `check` while deciding whether the gate refuses, and\n * calls `consume` after it has taken its own hold and before it charges: a\n * `false` from `consume` refuses the purchase, so one preclearance buys\n * exactly one thing.\n *\n * Only the named gate is waived. Every other refusal the plugin makes (a\n * brand lookalike, its per-workspace caps) stands, and an implementation has\n * no say in them.\n *\n * ## FAILS CLOSED\n *\n * {@link checkPurchaseGatePreclearance} answers null on any error and when\n * nothing is registered, and {@link consumePurchaseGatePreclearance} answers\n * false: a waiver that cannot be confirmed is no waiver, and the gate keeps\n * refusing.\n */\n\nimport {\n definePluginServiceContract,\n registerPluginService,\n resolvePluginServices,\n} from './plugin-services'\n\n/** The gates a preclearance may waive. One today. */\nexport type PurchaseGate = 'domain-payment-history'\n\nexport interface PurchaseGatePreclearanceInput {\n /** The workspace the purchase is for. */\n orgId: string\n gate: PurchaseGate\n}\n\nexport interface PurchaseGatePreclearance {\n /**\n * A live, unused waiver for this workspace and gate, or null. Reads only:\n * asking does not spend it.\n */\n check(input: PurchaseGatePreclearanceInput): Promise<{ preclearanceId: string } | null>\n /**\n * Spend the waiver: true exactly once per id, in a transaction that marks it\n * used only if nothing has. False for an id this implementation does not\n * hold, one already spent, or one that expired.\n */\n consume(preclearanceId: string): Promise<boolean>\n}\n\n/**\n * A set: more than one surface may mint a waiver (a bundle link today), and\n * the gate asks each in turn.\n */\nexport const PURCHASE_GATE_PRECLEARANCE =\n definePluginServiceContract<PurchaseGatePreclearance>('core.purchase-gate-preclearance', {\n multiple: true,\n })\n\n/** Installs an implementation. The console registers the bundle links at boot. */\nexport function registerPurchaseGatePreclearance(\n impl: PurchaseGatePreclearance,\n options?: { pluginId?: string; key?: string },\n): void {\n if (typeof impl?.check !== 'function' || typeof impl?.consume !== 'function') {\n throw new Error('a purchase gate preclearance needs check and consume functions')\n }\n registerPluginService(PURCHASE_GATE_PRECLEARANCE, impl, {\n ...(options?.pluginId ? { pluginId: options.pluginId } : {}),\n ...(options?.key ? { key: options.key } : {}),\n })\n}\n\n/**\n * The first live waiver any implementation holds for the workspace and gate,\n * or null. Never throws; an implementation that throws is skipped and\n * logged, so it can only ever cost a waiver, never grant one.\n */\nexport async function checkPurchaseGatePreclearance(\n input: PurchaseGatePreclearanceInput,\n): Promise<{ preclearanceId: string } | null> {\n const orgId = String(input?.orgId ?? '').trim()\n if (!orgId || input?.gate !== 'domain-payment-history') return null\n for (const registration of resolvePluginServices(PURCHASE_GATE_PRECLEARANCE)) {\n try {\n const found = await registration.impl.check({ orgId, gate: input.gate })\n const preclearanceId = String(found?.preclearanceId ?? '').trim()\n if (preclearanceId) return { preclearanceId }\n } catch (error) {\n console.error(\n `[purchase-gate-preclearance] check failed in \"${registration.pluginId}\"`,\n error,\n )\n }\n }\n return null\n}\n\n/**\n * Spend a waiver. True only when an implementation marked it used just now.\n * Never throws: a failure answers false, which refuses the purchase.\n */\nexport async function consumePurchaseGatePreclearance(\n preclearanceId: string,\n): Promise<boolean> {\n const id = String(preclearanceId ?? '').trim()\n if (!id) return false\n for (const registration of resolvePluginServices(PURCHASE_GATE_PRECLEARANCE)) {\n try {\n if ((await registration.impl.consume(id)) === true) return true\n } catch (error) {\n console.error(\n `[purchase-gate-preclearance] consume failed in \"${registration.pluginId}\"`,\n error,\n )\n }\n }\n return false\n}\n"],"names":["definePluginServiceContract","registerPluginService","resolvePluginServices","PURCHASE_GATE_PRECLEARANCE","multiple","registerPurchaseGatePreclearance","impl","options","check","consume","Error","pluginId","key","checkPurchaseGatePreclearance","input","orgId","String","trim","gate","registration","found","preclearanceId","error","console","consumePurchaseGatePreclearance","id"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GAED,SACEA,2BAA2B,EAC3BC,qBAAqB,EACrBC,qBAAqB,QAChB,uBAAmB;AAyB1B;;;CAGC,GACD,OAAO,MAAMC,6BACXH,4BAAsD,mCAAmC;IACvFI,UAAU;AACZ,GAAE;AAEJ,gFAAgF,GAChF,OAAO,SAASC,iCACdC,IAA8B,EAC9BC,OAA6C;IAE7C,IAAI,QAAOD,wBAAAA,KAAME,KAAK,MAAK,cAAc,QAAOF,wBAAAA,KAAMG,OAAO,MAAK,YAAY;QAC5E,MAAM,IAAIC,MAAM;IAClB;IACAT,sBAAsBE,4BAA4BG,MAAM,aAClDC,CAAAA,2BAAAA,QAASI,QAAQ,IAAG;QAAEA,UAAUJ,QAAQI,QAAQ;IAAC,IAAI,CAAC,GACtDJ,CAAAA,2BAAAA,QAASK,GAAG,IAAG;QAAEA,KAAKL,QAAQK,GAAG;IAAC,IAAI,CAAC;AAE/C;AAEA;;;;CAIC,GACD,OAAO,eAAeC,8BACpBC,KAAoC;;IAEpC,MAAMC,QAAQC,eAAOF,yBAAAA,MAAOC,KAAK,mBAAI,IAAIE,IAAI;IAC7C,IAAI,CAACF,SAASD,CAAAA,yBAAAA,MAAOI,IAAI,MAAK,0BAA0B,OAAO;IAC/D,KAAK,MAAMC,gBAAgBjB,sBAAsBC,4BAA6B;QAC5E,IAAI;;YACF,MAAMiB,QAAQ,MAAMD,aAAab,IAAI,CAACE,KAAK,CAAC;gBAAEO;gBAAOG,MAAMJ,MAAMI,IAAI;YAAC;YACtE,MAAMG,iBAAiBL,gBAAOI,yBAAAA,MAAOC,cAAc,oBAAI,IAAIJ,IAAI;YAC/D,IAAII,gBAAgB,OAAO;gBAAEA;YAAe;QAC9C,EAAE,OAAOC,OAAO;YACdC,QAAQD,KAAK,CACX,CAAC,8CAA8C,EAAEH,aAAaR,QAAQ,CAAC,CAAC,CAAC,EACzEW;QAEJ;IACF;IACA,OAAO;AACT;AAEA;;;CAGC,GACD,OAAO,eAAeE,gCACpBH,cAAsB;IAEtB,MAAMI,KAAKT,OAAOK,yBAAAA,iBAAkB,IAAIJ,IAAI;IAC5C,IAAI,CAACQ,IAAI,OAAO;IAChB,KAAK,MAAMN,gBAAgBjB,sBAAsBC,4BAA6B;QAC5E,IAAI;YACF,IAAI,AAAC,MAAMgB,aAAab,IAAI,CAACG,OAAO,CAACgB,QAAS,MAAM,OAAO;QAC7D,EAAE,OAAOH,OAAO;YACdC,QAAQD,KAAK,CACX,CAAC,gDAAgD,EAAEH,aAAaR,QAAQ,CAAC,CAAC,CAAC,EAC3EW;QAEJ;IACF;IACA,OAAO;AACT"}
|