@aglyn/aglyn 1.0.0-beta.202 → 1.0.0-beta.204
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/console-routes.d.ts +4 -0
- package/src/lib/app-utils/console-routes.js +4 -0
- package/src/lib/app-utils/console-routes.js.map +1 -1
- package/src/lib/app-utils/csv-import.d.ts +12 -0
- package/src/lib/app-utils/csv-import.js +13 -3
- package/src/lib/app-utils/csv-import.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +1 -1
- package/src/lib/app-utils/docs-help.generated.js +1 -0
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +76 -6
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/health-report.js +10 -0
- package/src/lib/app-utils/health-report.js.map +1 -1
- package/src/lib/app-utils/marketplace-listing-visibility.d.ts +1 -0
- package/src/lib/app-utils/marketplace-listing-visibility.js +6 -0
- package/src/lib/app-utils/marketplace-listing-visibility.js.map +1 -1
- package/src/lib/app-utils/notifications.d.ts +1 -1
- package/src/lib/app-utils/notifications.js +4 -1
- package/src/lib/app-utils/notifications.js.map +1 -1
- package/src/lib/app-utils/plan-entitlements.js +23 -0
- package/src/lib/app-utils/plan-entitlements.js.map +1 -1
- package/src/lib/app-utils/recipient-email-render.d.ts +21 -1
- package/src/lib/app-utils/recipient-email-render.js +34 -5
- package/src/lib/app-utils/recipient-email-render.js.map +1 -1
- package/src/lib/app-utils/server.d.ts +1 -1
- package/src/lib/app-utils/server.js +1 -1
- package/src/lib/app-utils/server.js.map +1 -1
- package/src/lib/app-utils/site-email-chrome.d.ts +52 -0
- package/src/lib/app-utils/site-email-chrome.js +82 -0
- package/src/lib/app-utils/site-email-chrome.js.map +1 -0
- package/src/lib/app-utils/system-email-chrome.d.ts +6 -0
- package/src/lib/app-utils/system-email-chrome.js.map +1 -1
- package/src/lib/plugin-manager/plugin-org-lockdown.d.ts +77 -0
- package/src/lib/plugin-manager/plugin-org-lockdown.js +88 -0
- package/src/lib/plugin-manager/plugin-org-lockdown.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-email-state.d.ts +7 -0
- package/src/lib/plugin-manager/plugin-record-email-state.js.map +1 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Where a lock records each payout schedule it paused (Admin SDK only; no
|
|
19
|
+
* client rule opens it). Named here, in core, so a plugin that manages a
|
|
20
|
+
* schedule of its own can tell that a lock holds the account and leave it be.
|
|
21
|
+
*/
|
|
22
|
+
export declare const LOCKDOWN_BILLING_PAUSES_COLLECTION = "lockdownBillingPauses";
|
|
23
|
+
/** The pause record's id for one connected account. */
|
|
24
|
+
export declare function lockdownPayoutPauseRecordId(accountId: string): string;
|
|
25
|
+
/** One connected account a plugin pays a workspace through. */
|
|
26
|
+
export interface PayoutAccountRecord {
|
|
27
|
+
/** The payment provider's account id (Stripe `acct_…`). */
|
|
28
|
+
accountId: string;
|
|
29
|
+
/** How staff read it: `marketplace publisher`. */
|
|
30
|
+
label: string;
|
|
31
|
+
}
|
|
32
|
+
export interface PayoutAccountSource {
|
|
33
|
+
/** The connected accounts this plugin pays `orgId` through. */
|
|
34
|
+
listPayoutAccounts(input: {
|
|
35
|
+
orgId: string;
|
|
36
|
+
}): Promise<PayoutAccountRecord[]>;
|
|
37
|
+
}
|
|
38
|
+
export declare const PLUGIN_PAYOUT_ACCOUNT_SOURCES: import("./plugin-services").PluginServiceContract<PayoutAccountSource>;
|
|
39
|
+
/** Declares the connected accounts a plugin pays workspaces through. */
|
|
40
|
+
export declare function registerPayoutAccountSource(source: PayoutAccountSource, options?: {
|
|
41
|
+
pluginId?: string;
|
|
42
|
+
}): void;
|
|
43
|
+
/** Every declared payout-account source, with the plugin that declared it. */
|
|
44
|
+
export declare function listPayoutAccountSources(): Array<{
|
|
45
|
+
pluginId: string;
|
|
46
|
+
source: PayoutAccountSource;
|
|
47
|
+
}>;
|
|
48
|
+
/** What a participant reports back for the staff log. */
|
|
49
|
+
export interface OrgLockdownParticipantResult {
|
|
50
|
+
/** One line a staff member reads: "Hid 3 marketplace listings". */
|
|
51
|
+
summary: string;
|
|
52
|
+
confirmed: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface OrgLockdownParticipant {
|
|
55
|
+
/** The workspace was locked (any reason), or lifted. */
|
|
56
|
+
onOrgLockChange(input: {
|
|
57
|
+
orgId: string;
|
|
58
|
+
locked: boolean;
|
|
59
|
+
reason: string | null;
|
|
60
|
+
}): Promise<OrgLockdownParticipantResult>;
|
|
61
|
+
}
|
|
62
|
+
export declare const PLUGIN_ORG_LOCKDOWN_PARTICIPANTS: import("./plugin-services").PluginServiceContract<OrgLockdownParticipant>;
|
|
63
|
+
/** Declares a plugin's part in a workspace lock. */
|
|
64
|
+
export declare function registerOrgLockdownParticipant(participant: OrgLockdownParticipant, options?: {
|
|
65
|
+
pluginId?: string;
|
|
66
|
+
}): void;
|
|
67
|
+
/**
|
|
68
|
+
* Tell every participant, one by one. Never throws: a participant that fails
|
|
69
|
+
* comes back as an unconfirmed line with its error.
|
|
70
|
+
*/
|
|
71
|
+
export declare function runOrgLockdownParticipants(input: {
|
|
72
|
+
orgId: string;
|
|
73
|
+
locked: boolean;
|
|
74
|
+
reason: string | null;
|
|
75
|
+
}): Promise<Array<{
|
|
76
|
+
pluginId: string;
|
|
77
|
+
} & OrgLockdownParticipantResult>>;
|
|
@@ -0,0 +1,88 @@
|
|
|
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
|
+
* WHAT A WORKSPACE LOCK REACHES IN A PLUGIN (AGL-3365).
|
|
19
|
+
*
|
|
20
|
+
* The lockdown is core; what a workspace owns inside a plugin is the
|
|
21
|
+
* plugin's. Two seams, beside `core.recurring-charge-sources` (AGL-3364):
|
|
22
|
+
*
|
|
23
|
+
* - `core.payout-account-sources` — the connected accounts a plugin pays a
|
|
24
|
+
* workspace through, beyond the storefront account core already knows
|
|
25
|
+
* (the owner's profile). A lock that pauses payouts pauses every one, and
|
|
26
|
+
* saves and restores each one's schedule on its own. The marketplace
|
|
27
|
+
* declares its publisher account here.
|
|
28
|
+
* - `core.org-lockdown-participants` — told when a workspace is locked or
|
|
29
|
+
* lifted, whatever the reason, after the lock is durable. The marketplace
|
|
30
|
+
* takes the workspace's listings out of browse and puts back exactly the
|
|
31
|
+
* ones it took.
|
|
32
|
+
*
|
|
33
|
+
* Neither may undo a lock: a participant that throws is reported as an
|
|
34
|
+
* unconfirmed step beside a lock that stands.
|
|
35
|
+
*=========================================*/ import { definePluginServiceContract, registerPluginService, resolvePluginServices } from "./plugin-services.js";
|
|
36
|
+
/**
|
|
37
|
+
* Where a lock records each payout schedule it paused (Admin SDK only; no
|
|
38
|
+
* client rule opens it). Named here, in core, so a plugin that manages a
|
|
39
|
+
* schedule of its own can tell that a lock holds the account and leave it be.
|
|
40
|
+
*/ export const LOCKDOWN_BILLING_PAUSES_COLLECTION = 'lockdownBillingPauses';
|
|
41
|
+
/** The pause record's id for one connected account. */ export function lockdownPayoutPauseRecordId(accountId) {
|
|
42
|
+
return `payout_${accountId}`;
|
|
43
|
+
}
|
|
44
|
+
export const PLUGIN_PAYOUT_ACCOUNT_SOURCES = definePluginServiceContract('core.payout-account-sources', {
|
|
45
|
+
multiple: true
|
|
46
|
+
});
|
|
47
|
+
/** Declares the connected accounts a plugin pays workspaces through. */ export function registerPayoutAccountSource(source, options) {
|
|
48
|
+
registerPluginService(PLUGIN_PAYOUT_ACCOUNT_SOURCES, source, _extends({}, (options == null ? void 0 : options.pluginId) ? {
|
|
49
|
+
pluginId: options.pluginId
|
|
50
|
+
} : {}));
|
|
51
|
+
}
|
|
52
|
+
/** Every declared payout-account source, with the plugin that declared it. */ export function listPayoutAccountSources() {
|
|
53
|
+
return resolvePluginServices(PLUGIN_PAYOUT_ACCOUNT_SOURCES).map((entry)=>({
|
|
54
|
+
pluginId: entry.pluginId,
|
|
55
|
+
source: entry.impl
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
export const PLUGIN_ORG_LOCKDOWN_PARTICIPANTS = definePluginServiceContract('core.org-lockdown-participants', {
|
|
59
|
+
multiple: true
|
|
60
|
+
});
|
|
61
|
+
/** Declares a plugin's part in a workspace lock. */ export function registerOrgLockdownParticipant(participant, options) {
|
|
62
|
+
registerPluginService(PLUGIN_ORG_LOCKDOWN_PARTICIPANTS, participant, _extends({}, (options == null ? void 0 : options.pluginId) ? {
|
|
63
|
+
pluginId: options.pluginId
|
|
64
|
+
} : {}));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Tell every participant, one by one. Never throws: a participant that fails
|
|
68
|
+
* comes back as an unconfirmed line with its error.
|
|
69
|
+
*/ export async function runOrgLockdownParticipants(input) {
|
|
70
|
+
const results = [];
|
|
71
|
+
for (const entry of resolvePluginServices(PLUGIN_ORG_LOCKDOWN_PARTICIPANTS)){
|
|
72
|
+
try {
|
|
73
|
+
results.push(_extends({
|
|
74
|
+
pluginId: entry.pluginId
|
|
75
|
+
}, await entry.impl.onOrgLockChange(input)));
|
|
76
|
+
} catch (error) {
|
|
77
|
+
var _ref;
|
|
78
|
+
results.push({
|
|
79
|
+
pluginId: entry.pluginId,
|
|
80
|
+
summary: `Did not run: ${(_ref = error == null ? void 0 : error.message) != null ? _ref : String(error)}`,
|
|
81
|
+
confirmed: false
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=plugin-org-lockdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-org-lockdown.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 * WHAT A WORKSPACE LOCK REACHES IN A PLUGIN (AGL-3365).\n *\n * The lockdown is core; what a workspace owns inside a plugin is the\n * plugin's. Two seams, beside `core.recurring-charge-sources` (AGL-3364):\n *\n * - `core.payout-account-sources` — the connected accounts a plugin pays a\n * workspace through, beyond the storefront account core already knows\n * (the owner's profile). A lock that pauses payouts pauses every one, and\n * saves and restores each one's schedule on its own. The marketplace\n * declares its publisher account here.\n * - `core.org-lockdown-participants` — told when a workspace is locked or\n * lifted, whatever the reason, after the lock is durable. The marketplace\n * takes the workspace's listings out of browse and puts back exactly the\n * ones it took.\n *\n * Neither may undo a lock: a participant that throws is reported as an\n * unconfirmed step beside a lock that stands.\n *=========================================*/\n\nimport {\n definePluginServiceContract,\n registerPluginService,\n resolvePluginServices,\n} from './plugin-services'\n\n/**\n * Where a lock records each payout schedule it paused (Admin SDK only; no\n * client rule opens it). Named here, in core, so a plugin that manages a\n * schedule of its own can tell that a lock holds the account and leave it be.\n */\nexport const LOCKDOWN_BILLING_PAUSES_COLLECTION = 'lockdownBillingPauses'\n\n/** The pause record's id for one connected account. */\nexport function lockdownPayoutPauseRecordId(accountId: string): string {\n return `payout_${accountId}`\n}\n\n/** One connected account a plugin pays a workspace through. */\nexport interface PayoutAccountRecord {\n /** The payment provider's account id (Stripe `acct_…`). */\n accountId: string\n /** How staff read it: `marketplace publisher`. */\n label: string\n}\n\nexport interface PayoutAccountSource {\n /** The connected accounts this plugin pays `orgId` through. */\n listPayoutAccounts(input: { orgId: string }): Promise<PayoutAccountRecord[]>\n}\n\nexport const PLUGIN_PAYOUT_ACCOUNT_SOURCES =\n definePluginServiceContract<PayoutAccountSource>('core.payout-account-sources', {\n multiple: true,\n })\n\n/** Declares the connected accounts a plugin pays workspaces through. */\nexport function registerPayoutAccountSource(\n source: PayoutAccountSource,\n options?: { pluginId?: string },\n): void {\n registerPluginService(PLUGIN_PAYOUT_ACCOUNT_SOURCES, source, {\n ...(options?.pluginId ? { pluginId: options.pluginId } : {}),\n })\n}\n\n/** Every declared payout-account source, with the plugin that declared it. */\nexport function listPayoutAccountSources(): Array<{\n pluginId: string\n source: PayoutAccountSource\n}> {\n return resolvePluginServices(PLUGIN_PAYOUT_ACCOUNT_SOURCES).map((entry) => ({\n pluginId: entry.pluginId,\n source: entry.impl,\n }))\n}\n\n/** What a participant reports back for the staff log. */\nexport interface OrgLockdownParticipantResult {\n /** One line a staff member reads: \"Hid 3 marketplace listings\". */\n summary: string\n confirmed: boolean\n}\n\nexport interface OrgLockdownParticipant {\n /** The workspace was locked (any reason), or lifted. */\n onOrgLockChange(input: {\n orgId: string\n locked: boolean\n reason: string | null\n }): Promise<OrgLockdownParticipantResult>\n}\n\nexport const PLUGIN_ORG_LOCKDOWN_PARTICIPANTS =\n definePluginServiceContract<OrgLockdownParticipant>('core.org-lockdown-participants', {\n multiple: true,\n })\n\n/** Declares a plugin's part in a workspace lock. */\nexport function registerOrgLockdownParticipant(\n participant: OrgLockdownParticipant,\n options?: { pluginId?: string },\n): void {\n registerPluginService(PLUGIN_ORG_LOCKDOWN_PARTICIPANTS, participant, {\n ...(options?.pluginId ? { pluginId: options.pluginId } : {}),\n })\n}\n\n/**\n * Tell every participant, one by one. Never throws: a participant that fails\n * comes back as an unconfirmed line with its error.\n */\nexport async function runOrgLockdownParticipants(input: {\n orgId: string\n locked: boolean\n reason: string | null\n}): Promise<Array<{ pluginId: string } & OrgLockdownParticipantResult>> {\n const results: Array<{ pluginId: string } & OrgLockdownParticipantResult> = []\n for (const entry of resolvePluginServices(PLUGIN_ORG_LOCKDOWN_PARTICIPANTS)) {\n try {\n results.push({ pluginId: entry.pluginId, ...(await entry.impl.onOrgLockChange(input)) })\n } catch (error) {\n results.push({\n pluginId: entry.pluginId,\n summary: `Did not run: ${(error as Error)?.message ?? String(error)}`,\n confirmed: false,\n })\n }\n }\n return results\n}\n"],"names":["definePluginServiceContract","registerPluginService","resolvePluginServices","LOCKDOWN_BILLING_PAUSES_COLLECTION","lockdownPayoutPauseRecordId","accountId","PLUGIN_PAYOUT_ACCOUNT_SOURCES","multiple","registerPayoutAccountSource","source","options","pluginId","listPayoutAccountSources","map","entry","impl","PLUGIN_ORG_LOCKDOWN_PARTICIPANTS","registerOrgLockdownParticipant","participant","runOrgLockdownParticipants","input","results","push","onOrgLockChange","error","summary","message","String","confirmed"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;2CAkB2C,GAE3C,SACEA,2BAA2B,EAC3BC,qBAAqB,EACrBC,qBAAqB,QAChB,uBAAmB;AAE1B;;;;CAIC,GACD,OAAO,MAAMC,qCAAqC,wBAAuB;AAEzE,qDAAqD,GACrD,OAAO,SAASC,4BAA4BC,SAAiB;IAC3D,OAAO,CAAC,OAAO,EAAEA,WAAW;AAC9B;AAeA,OAAO,MAAMC,gCACXN,4BAAiD,+BAA+B;IAC9EO,UAAU;AACZ,GAAE;AAEJ,sEAAsE,GACtE,OAAO,SAASC,4BACdC,MAA2B,EAC3BC,OAA+B;IAE/BT,sBAAsBK,+BAA+BG,QAAQ,aACvDC,CAAAA,2BAAAA,QAASC,QAAQ,IAAG;QAAEA,UAAUD,QAAQC,QAAQ;IAAC,IAAI,CAAC;AAE9D;AAEA,4EAA4E,GAC5E,OAAO,SAASC;IAId,OAAOV,sBAAsBI,+BAA+BO,GAAG,CAAC,CAACC,QAAW,CAAA;YAC1EH,UAAUG,MAAMH,QAAQ;YACxBF,QAAQK,MAAMC,IAAI;QACpB,CAAA;AACF;AAkBA,OAAO,MAAMC,mCACXhB,4BAAoD,kCAAkC;IACpFO,UAAU;AACZ,GAAE;AAEJ,kDAAkD,GAClD,OAAO,SAASU,+BACdC,WAAmC,EACnCR,OAA+B;IAE/BT,sBAAsBe,kCAAkCE,aAAa,aAC/DR,CAAAA,2BAAAA,QAASC,QAAQ,IAAG;QAAEA,UAAUD,QAAQC,QAAQ;IAAC,IAAI,CAAC;AAE9D;AAEA;;;CAGC,GACD,OAAO,eAAeQ,2BAA2BC,KAIhD;IACC,MAAMC,UAAsE,EAAE;IAC9E,KAAK,MAAMP,SAASZ,sBAAsBc,kCAAmC;QAC3E,IAAI;YACFK,QAAQC,IAAI,CAAC;gBAAEX,UAAUG,MAAMH,QAAQ;eAAM,MAAMG,MAAMC,IAAI,CAACQ,eAAe,CAACH;QAChF,EAAE,OAAOI,OAAO;;YACdH,QAAQC,IAAI,CAAC;gBACXX,UAAUG,MAAMH,QAAQ;gBACxBc,SAAS,CAAC,aAAa,UAAGD,yBAAD,AAACA,MAAiBE,OAAO,mBAAIC,OAAOH,QAAQ;gBACrEI,WAAW;YACb;QACF;IACF;IACA,OAAOP;AACT"}
|
|
@@ -51,6 +51,13 @@ export interface PluginRecordEmailStateRequest {
|
|
|
51
51
|
state: EmailState;
|
|
52
52
|
/** Write the state whatever the record holds — a release. */
|
|
53
53
|
force?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Take the verdict back instead of writing it: a record whose standing
|
|
56
|
+
* state has `state.status` loses it, and any other record is left alone.
|
|
57
|
+
* The deliverability check's way back from `undeliverable` once the
|
|
58
|
+
* domain takes mail (AGL-3328); it never clears a verdict it did not give.
|
|
59
|
+
*/
|
|
60
|
+
withdraw?: boolean;
|
|
54
61
|
}
|
|
55
62
|
export interface PluginRecordEmailStateReport {
|
|
56
63
|
/** Records whose state moved. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-record-email-state.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 { EmailState } from '../app-utils/email-state'\nimport {\n definePluginServiceContract,\n registerPluginService,\n resolvePluginServices,\n} from './plugin-services'\n\n/**\n * The verdict on an address, written onto the records that carry it\n * (AGL-3245).\n *\n * The senders keep their lists — the platform's suppression list, a site's\n * suppressions, an organization's do-not-contact list — and those are what\n * a send consults. The record a person reads is the record system's: a\n * lead, a contact, whatever the plugin that keeps the workspace's records\n * calls them. A sender must not write that plugin's documents itself, nor\n * import it; so the record system registers a WRITER here, and a sender\n * that filed a verdict on a list says so through it.\n *\n * The writer finds every record the address is — the plugin knows its own\n * storage and its own index — and stamps `emailState` on each, keeping the\n * stronger verdict (`nextEmailState`). A single-implementation contract: a\n * workspace keeps one record system.\n *\n * ## The caller proves who is asking\n *\n * Like the timeline seam, the registry authenticates nobody. The caller\n * decides, in its own terms and before it asks, that the verdict is the\n * workspace's to write: an address it sent to, a list it wrote.\n */\n\nexport interface PluginRecordEmailStateRequest {\n /** The organization whose records are stamped. */\n orgId?: string\n /**\n * Or the site the send left from, when the caller knows only that — a\n * campaign webhook, an unsubscribe link. The writer reads the\n * organization off it.\n */\n hostId?: string\n email: string\n state: EmailState\n /** Write the state whatever the record holds — a release. */\n force?: boolean\n}\n\nexport interface PluginRecordEmailStateReport {\n /** Records whose state moved. */\n records: number\n}\n\nexport interface PluginRecordEmailStateWriter {\n /** Never throws: a list is the control, the stamp is what a person reads. */\n stamp(request: PluginRecordEmailStateRequest): Promise<PluginRecordEmailStateReport>\n}\n\nexport const PLUGIN_RECORD_EMAIL_STATE = definePluginServiceContract<PluginRecordEmailStateWriter>(\n 'core.record-email-state',\n { multiple: false },\n)\n\n/**\n * Registers the workspace's record email-state writer. The owner is the\n * loader's marker when a register fn is running, else `options.pluginId`;\n * with neither the registration throws, and a second plugin's writer is\n * refused naming both — the incumbent keeps serving.\n */\nexport function registerPluginRecordEmailStateWriter(\n writer: PluginRecordEmailStateWriter,\n options?: { pluginId?: string },\n): void {\n registerPluginService(PLUGIN_RECORD_EMAIL_STATE, writer, {\n ...(options?.pluginId ? { pluginId: options.pluginId } : {}),\n })\n}\n\nexport interface ResolvedPluginRecordEmailStateWriter {\n /** The plugin that keeps the records. */\n pluginId: string\n writer: PluginRecordEmailStateWriter\n}\n\n/** The writer, with its owner, or `null` when no plugin keeps records here. */\nexport function pluginRecordEmailStateWriter(): ResolvedPluginRecordEmailStateWriter | null {\n const entry = resolvePluginServices(PLUGIN_RECORD_EMAIL_STATE)[0]\n return entry ? { pluginId: entry.pluginId, writer: entry.impl } : null\n}\n\n/**\n * Stamps the verdict through whichever plugin keeps the records, or answers\n * `null` when none does. Never throws: every caller is a sender for whom\n * the stamp is a courtesy beside the list it already wrote.\n */\nexport async function stampRecordEmailState(\n request: PluginRecordEmailStateRequest,\n): Promise<PluginRecordEmailStateReport | null> {\n const resolved = pluginRecordEmailStateWriter()\n if (!resolved) return null\n try {\n return await resolved.writer.stamp(request)\n } catch (error) {\n console.error('[record-email-state] the record system could not stamp the address', error)\n return null\n }\n}\n"],"names":["definePluginServiceContract","registerPluginService","resolvePluginServices","PLUGIN_RECORD_EMAIL_STATE","multiple","registerPluginRecordEmailStateWriter","writer","options","pluginId","pluginRecordEmailStateWriter","entry","impl","stampRecordEmailState","request","resolved","stamp","error","console"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AAGD,SACEA,2BAA2B,EAC3BC,qBAAqB,EACrBC,qBAAqB,QAChB,uBAAmB;
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/plugin-manager/plugin-record-email-state.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 { EmailState } from '../app-utils/email-state'\nimport {\n definePluginServiceContract,\n registerPluginService,\n resolvePluginServices,\n} from './plugin-services'\n\n/**\n * The verdict on an address, written onto the records that carry it\n * (AGL-3245).\n *\n * The senders keep their lists — the platform's suppression list, a site's\n * suppressions, an organization's do-not-contact list — and those are what\n * a send consults. The record a person reads is the record system's: a\n * lead, a contact, whatever the plugin that keeps the workspace's records\n * calls them. A sender must not write that plugin's documents itself, nor\n * import it; so the record system registers a WRITER here, and a sender\n * that filed a verdict on a list says so through it.\n *\n * The writer finds every record the address is — the plugin knows its own\n * storage and its own index — and stamps `emailState` on each, keeping the\n * stronger verdict (`nextEmailState`). A single-implementation contract: a\n * workspace keeps one record system.\n *\n * ## The caller proves who is asking\n *\n * Like the timeline seam, the registry authenticates nobody. The caller\n * decides, in its own terms and before it asks, that the verdict is the\n * workspace's to write: an address it sent to, a list it wrote.\n */\n\nexport interface PluginRecordEmailStateRequest {\n /** The organization whose records are stamped. */\n orgId?: string\n /**\n * Or the site the send left from, when the caller knows only that — a\n * campaign webhook, an unsubscribe link. The writer reads the\n * organization off it.\n */\n hostId?: string\n email: string\n state: EmailState\n /** Write the state whatever the record holds — a release. */\n force?: boolean\n /**\n * Take the verdict back instead of writing it: a record whose standing\n * state has `state.status` loses it, and any other record is left alone.\n * The deliverability check's way back from `undeliverable` once the\n * domain takes mail (AGL-3328); it never clears a verdict it did not give.\n */\n withdraw?: boolean\n}\n\nexport interface PluginRecordEmailStateReport {\n /** Records whose state moved. */\n records: number\n}\n\nexport interface PluginRecordEmailStateWriter {\n /** Never throws: a list is the control, the stamp is what a person reads. */\n stamp(request: PluginRecordEmailStateRequest): Promise<PluginRecordEmailStateReport>\n}\n\nexport const PLUGIN_RECORD_EMAIL_STATE = definePluginServiceContract<PluginRecordEmailStateWriter>(\n 'core.record-email-state',\n { multiple: false },\n)\n\n/**\n * Registers the workspace's record email-state writer. The owner is the\n * loader's marker when a register fn is running, else `options.pluginId`;\n * with neither the registration throws, and a second plugin's writer is\n * refused naming both — the incumbent keeps serving.\n */\nexport function registerPluginRecordEmailStateWriter(\n writer: PluginRecordEmailStateWriter,\n options?: { pluginId?: string },\n): void {\n registerPluginService(PLUGIN_RECORD_EMAIL_STATE, writer, {\n ...(options?.pluginId ? { pluginId: options.pluginId } : {}),\n })\n}\n\nexport interface ResolvedPluginRecordEmailStateWriter {\n /** The plugin that keeps the records. */\n pluginId: string\n writer: PluginRecordEmailStateWriter\n}\n\n/** The writer, with its owner, or `null` when no plugin keeps records here. */\nexport function pluginRecordEmailStateWriter(): ResolvedPluginRecordEmailStateWriter | null {\n const entry = resolvePluginServices(PLUGIN_RECORD_EMAIL_STATE)[0]\n return entry ? { pluginId: entry.pluginId, writer: entry.impl } : null\n}\n\n/**\n * Stamps the verdict through whichever plugin keeps the records, or answers\n * `null` when none does. Never throws: every caller is a sender for whom\n * the stamp is a courtesy beside the list it already wrote.\n */\nexport async function stampRecordEmailState(\n request: PluginRecordEmailStateRequest,\n): Promise<PluginRecordEmailStateReport | null> {\n const resolved = pluginRecordEmailStateWriter()\n if (!resolved) return null\n try {\n return await resolved.writer.stamp(request)\n } catch (error) {\n console.error('[record-email-state] the record system could not stamp the address', error)\n return null\n }\n}\n"],"names":["definePluginServiceContract","registerPluginService","resolvePluginServices","PLUGIN_RECORD_EMAIL_STATE","multiple","registerPluginRecordEmailStateWriter","writer","options","pluginId","pluginRecordEmailStateWriter","entry","impl","stampRecordEmailState","request","resolved","stamp","error","console"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AAGD,SACEA,2BAA2B,EAC3BC,qBAAqB,EACrBC,qBAAqB,QAChB,uBAAmB;AA0D1B,OAAO,MAAMC,4BAA4BH,4BACvC,2BACA;IAAEI,UAAU;AAAM,GACnB;AAED;;;;;CAKC,GACD,OAAO,SAASC,qCACdC,MAAoC,EACpCC,OAA+B;IAE/BN,sBAAsBE,2BAA2BG,QAAQ,aACnDC,CAAAA,2BAAAA,QAASC,QAAQ,IAAG;QAAEA,UAAUD,QAAQC,QAAQ;IAAC,IAAI,CAAC;AAE9D;AAQA,6EAA6E,GAC7E,OAAO,SAASC;IACd,MAAMC,QAAQR,sBAAsBC,0BAA0B,CAAC,EAAE;IACjE,OAAOO,QAAQ;QAAEF,UAAUE,MAAMF,QAAQ;QAAEF,QAAQI,MAAMC,IAAI;IAAC,IAAI;AACpE;AAEA;;;;CAIC,GACD,OAAO,eAAeC,sBACpBC,OAAsC;IAEtC,MAAMC,WAAWL;IACjB,IAAI,CAACK,UAAU,OAAO;IACtB,IAAI;QACF,OAAO,MAAMA,SAASR,MAAM,CAACS,KAAK,CAACF;IACrC,EAAE,OAAOG,OAAO;QACdC,QAAQD,KAAK,CAAC,sEAAsEA;QACpF,OAAO;IACT;AACF"}
|