@aglyn/tenant-data-admin 1.0.0-beta.200 → 1.0.0-beta.202
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 +8 -7
- package/src/lib/server/card-payment-velocity.d.ts +85 -0
- package/src/lib/server/card-payment-velocity.js +202 -0
- package/src/lib/server/card-payment-velocity.js.map +1 -0
- package/src/lib/server/configured-url-fetch.d.ts +42 -0
- package/src/lib/server/configured-url-fetch.js +118 -0
- package/src/lib/server/configured-url-fetch.js.map +1 -0
- package/src/lib/server/dns-probe.d.ts +7 -0
- package/src/lib/server/dns-probe.js +52 -0
- package/src/lib/server/dns-probe.js.map +1 -1
- package/src/lib/server/email-deliverability.d.ts +150 -0
- package/src/lib/server/email-deliverability.js +538 -0
- package/src/lib/server/email-deliverability.js.map +1 -0
- package/src/lib/server/email-sender-reputation.d.ts +2 -11
- package/src/lib/server/email-sender-reputation.js +8 -25
- package/src/lib/server/email-sender-reputation.js.map +1 -1
- package/src/lib/server/email-suppression.d.ts +10 -1
- package/src/lib/server/email-suppression.js +4 -3
- package/src/lib/server/email-suppression.js.map +1 -1
- package/src/lib/server/erase-person.js +31 -3
- package/src/lib/server/erase-person.js.map +1 -1
- package/src/lib/server/host-visitor-records.d.ts +16 -2
- package/src/lib/server/host-visitor-records.js +31 -6
- package/src/lib/server/host-visitor-records.js.map +1 -1
- package/src/lib/server/hosted-page-review.d.ts +112 -0
- package/src/lib/server/hosted-page-review.js +378 -0
- package/src/lib/server/hosted-page-review.js.map +1 -0
- package/src/lib/server/member-email-aliases.js +18 -7
- package/src/lib/server/member-email-aliases.js.map +1 -1
- package/src/lib/server/notifications.d.ts +8 -0
- package/src/lib/server/notifications.js +92 -17
- package/src/lib/server/notifications.js.map +1 -1
- package/src/lib/server/org-age.d.ts +27 -0
- package/src/lib/server/org-age.js +44 -0
- package/src/lib/server/org-age.js.map +1 -0
- package/src/lib/server/org-member-notice.js +20 -5
- package/src/lib/server/org-member-notice.js.map +1 -1
- package/src/lib/server/organizations.d.ts +10 -1
- package/src/lib/server/organizations.js +12 -4
- package/src/lib/server/organizations.js.map +1 -1
- package/src/lib/server/outbound-send-review.d.ts +224 -0
- package/src/lib/server/outbound-send-review.js +479 -0
- package/src/lib/server/outbound-send-review.js.map +1 -0
- package/src/lib/server/payment-fraud-signal.d.ts +156 -0
- package/src/lib/server/payment-fraud-signal.js +368 -0
- package/src/lib/server/payment-fraud-signal.js.map +1 -0
- package/src/lib/server/payment-risk-record.d.ts +59 -0
- package/src/lib/server/payment-risk-record.js +76 -0
- package/src/lib/server/payment-risk-record.js.map +1 -0
- package/src/lib/server/render-system-email.d.ts +176 -0
- package/src/lib/server/render-system-email.js +315 -0
- package/src/lib/server/render-system-email.js.map +1 -0
- package/src/lib/server/sending-domains.d.ts +6 -0
- package/src/lib/server/sending-domains.js +98 -6
- package/src/lib/server/sending-domains.js.map +1 -1
- package/src/lib/server/staff-alert-email.d.ts +2 -1
- package/src/lib/server/staff-alert-email.js +16 -5
- package/src/lib/server/staff-alert-email.js.map +1 -1
- package/src/lib/server/stripe-card-authentication.d.ts +35 -0
- package/src/lib/server/stripe-card-authentication.js +63 -0
- package/src/lib/server/stripe-card-authentication.js.map +1 -0
- package/src/lib/server/tenant-write-lockdown.d.ts +32 -2
- package/src/lib/server/tenant-write-lockdown.js +33 -3
- package/src/lib/server/tenant-write-lockdown.js.map +1 -1
- package/src/tenancy.d.ts +5 -0
- package/src/tenancy.js +10 -0
- package/src/tenancy.js.map +1 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /*==========================================
|
|
17
|
+
* 3-D SECURE, AT ONE SEAM (AGL-3356, AGL-3360).
|
|
18
|
+
*
|
|
19
|
+
* Every card payment and every card saved on Aglyn asks Stripe for 3-D
|
|
20
|
+
* Secure through this one function: the workspace's own SetupIntent, and
|
|
21
|
+
* every Checkout Session a plugin opens for a site's customer (storefront,
|
|
22
|
+
* cart, draft order, POS, reservation, booking deposit, marketplace).
|
|
23
|
+
*
|
|
24
|
+
* TWO ANSWERS, by what the card is for:
|
|
25
|
+
*
|
|
26
|
+
* - `one-time`: `automatic`. Stripe authenticates when the issuer requires
|
|
27
|
+
* it (SCA) or when Radar asks (a "request 3D Secure" rule). A shopper is
|
|
28
|
+
* not challenged for a routine purchase, and a merchant's Radar rules can
|
|
29
|
+
* still raise the bar. This is Stripe's default today; sending it
|
|
30
|
+
* explicitly keeps the choice ours if the default moves.
|
|
31
|
+
* - `off-session`: `any`. The card is kept and charged later with nobody
|
|
32
|
+
* present (a membership renewal, the workspace's own plan). Authenticating
|
|
33
|
+
* once now is what lets the issuer approve the unattended renewals, and it
|
|
34
|
+
* moves fraud liability to the issuer. A card without 3DS still works.
|
|
35
|
+
*
|
|
36
|
+
* ONE CHALLENGE PER PAYMENT. The parameter is the whole request: Checkout
|
|
37
|
+
* and `confirmSetup` run the challenge themselves when Stripe answers
|
|
38
|
+
* `requires_action`, and a subscription's first invoice is authenticated
|
|
39
|
+
* by the same step that saves the card. Nothing here adds a second prompt.
|
|
40
|
+
*
|
|
41
|
+
* Pure and dependency-free, so every plugin and the console share it
|
|
42
|
+
* without a bundle cost.
|
|
43
|
+
*=========================================*/ /** What the card is being collected for. */ /** The param name, identical on PaymentIntents, SetupIntents and Checkout Sessions. */ export const REQUEST_THREE_D_SECURE_PARAM = 'payment_method_options[card][request_three_d_secure]';
|
|
44
|
+
/** `automatic` for a one-time payment, `any` for a card kept for later. */ export function requestThreeDSecureFor(use) {
|
|
45
|
+
return use === 'off-session' ? 'any' : 'automatic';
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The form-encoded params to spread into a Stripe request body, beside the
|
|
49
|
+
* request's own fields in the `URLSearchParams` it builds.
|
|
50
|
+
*/ export function cardAuthenticationParams(use) {
|
|
51
|
+
return {
|
|
52
|
+
[REQUEST_THREE_D_SECURE_PARAM]: requestThreeDSecureFor(use)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The same params for a Checkout Session, chosen by its `mode`: a
|
|
57
|
+
* `subscription` or `setup` session keeps the card for off-session charges,
|
|
58
|
+
* a `payment` session does not.
|
|
59
|
+
*/ export function checkoutSessionCardAuthenticationParams(mode) {
|
|
60
|
+
return cardAuthenticationParams(mode === 'payment' ? 'one-time' : 'off-session');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=stripe-card-authentication.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/tenant/data/admin/src/lib/server/stripe-card-authentication.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 * 3-D SECURE, AT ONE SEAM (AGL-3356, AGL-3360).\n *\n * Every card payment and every card saved on Aglyn asks Stripe for 3-D\n * Secure through this one function: the workspace's own SetupIntent, and\n * every Checkout Session a plugin opens for a site's customer (storefront,\n * cart, draft order, POS, reservation, booking deposit, marketplace).\n *\n * TWO ANSWERS, by what the card is for:\n *\n * - `one-time`: `automatic`. Stripe authenticates when the issuer requires\n * it (SCA) or when Radar asks (a \"request 3D Secure\" rule). A shopper is\n * not challenged for a routine purchase, and a merchant's Radar rules can\n * still raise the bar. This is Stripe's default today; sending it\n * explicitly keeps the choice ours if the default moves.\n * - `off-session`: `any`. The card is kept and charged later with nobody\n * present (a membership renewal, the workspace's own plan). Authenticating\n * once now is what lets the issuer approve the unattended renewals, and it\n * moves fraud liability to the issuer. A card without 3DS still works.\n *\n * ONE CHALLENGE PER PAYMENT. The parameter is the whole request: Checkout\n * and `confirmSetup` run the challenge themselves when Stripe answers\n * `requires_action`, and a subscription's first invoice is authenticated\n * by the same step that saves the card. Nothing here adds a second prompt.\n *\n * Pure and dependency-free, so every plugin and the console share it\n * without a bundle cost.\n *=========================================*/\n\n/** What the card is being collected for. */\nexport type CardAuthenticationUse = 'one-time' | 'off-session'\n\n/** The value Stripe's `request_three_d_secure` takes. */\nexport type RequestThreeDSecure = 'automatic' | 'any'\n\n/** The param name, identical on PaymentIntents, SetupIntents and Checkout Sessions. */\nexport const REQUEST_THREE_D_SECURE_PARAM =\n 'payment_method_options[card][request_three_d_secure]'\n\n/** `automatic` for a one-time payment, `any` for a card kept for later. */\nexport function requestThreeDSecureFor(\n use: CardAuthenticationUse,\n): RequestThreeDSecure {\n return use === 'off-session' ? 'any' : 'automatic'\n}\n\n/**\n * The form-encoded params to spread into a Stripe request body, beside the\n * request's own fields in the `URLSearchParams` it builds.\n */\nexport function cardAuthenticationParams(\n use: CardAuthenticationUse,\n): Record<string, string> {\n return { [REQUEST_THREE_D_SECURE_PARAM]: requestThreeDSecureFor(use) }\n}\n\n/**\n * The same params for a Checkout Session, chosen by its `mode`: a\n * `subscription` or `setup` session keeps the card for off-session charges,\n * a `payment` session does not.\n */\nexport function checkoutSessionCardAuthenticationParams(\n mode: 'payment' | 'subscription' | 'setup',\n): Record<string, string> {\n return cardAuthenticationParams(mode === 'payment' ? 'one-time' : 'off-session')\n}\n"],"names":["REQUEST_THREE_D_SECURE_PARAM","requestThreeDSecureFor","use","cardAuthenticationParams","checkoutSessionCardAuthenticationParams","mode"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;2CA2B2C,GAE3C,0CAA0C,GAM1C,qFAAqF,GACrF,OAAO,MAAMA,+BACX,uDAAsD;AAExD,yEAAyE,GACzE,OAAO,SAASC,uBACdC,GAA0B;IAE1B,OAAOA,QAAQ,gBAAgB,QAAQ;AACzC;AAEA;;;CAGC,GACD,OAAO,SAASC,yBACdD,GAA0B;IAE1B,OAAO;QAAE,CAACF,6BAA6B,EAAEC,uBAAuBC;IAAK;AACvE;AAEA;;;;CAIC,GACD,OAAO,SAASE,wCACdC,IAA0C;IAE1C,OAAOF,yBAAyBE,SAAS,YAAY,aAAa;AACpE"}
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
* a public website, the caller is anonymous, and a visitor's identity plays
|
|
43
43
|
* no part in whether a site accepts an order.
|
|
44
44
|
*/
|
|
45
|
-
import { type LockdownIntent, type LockdownPausedSurface, type LockdownState } from '@aglyn/aglyn/server';
|
|
45
|
+
import { type LockdownIntent, type LockdownPausedSurface, type LockdownState, type PluginJobHostGate } from '@aglyn/aglyn/server';
|
|
46
46
|
/**
|
|
47
47
|
* The active platform/org/host lockdown for one site, or null.
|
|
48
48
|
*
|
|
@@ -72,7 +72,37 @@ import { type LockdownIntent, type LockdownPausedSurface, type LockdownState } f
|
|
|
72
72
|
* every shop on the platform offline on any transient blip, which is the
|
|
73
73
|
* deliberate posture this keeps for the default case.
|
|
74
74
|
*/
|
|
75
|
-
export declare function getSiteLockdown(hostId: string, nowMs?: number
|
|
75
|
+
export declare function getSiteLockdown(hostId: string, nowMs?: number,
|
|
76
|
+
/**
|
|
77
|
+
* The org and host documents, when the caller has already read them — a
|
|
78
|
+
* sender resolving its identity holds both, and outside a request scope
|
|
79
|
+
* `React.cache` dedupes nothing, so reading them again here would double
|
|
80
|
+
* the reads on every message. `undefined` for either one means "not
|
|
81
|
+
* loaded, read it"; `null` means "read, and there is none".
|
|
82
|
+
*/
|
|
83
|
+
loaded?: {
|
|
84
|
+
org?: Record<string, unknown> | null;
|
|
85
|
+
host?: Record<string, unknown> | null;
|
|
86
|
+
}): Promise<LockdownState | null>;
|
|
87
|
+
/**
|
|
88
|
+
* The background-work gate over {@link getSiteLockdown}: ANY active lock on
|
|
89
|
+
* the site answers locked (AGL-2495, AGL-3356).
|
|
90
|
+
*
|
|
91
|
+
* One definition, two doors. The tenant's job runner registers
|
|
92
|
+
* `isLocked` as core's job resolver (`apps/tenant/utils/plugin-job-lockdown`),
|
|
93
|
+
* and the `x-cron-secret` doors that drive the same scans by hand in the
|
|
94
|
+
* CONSOLE — abandoned carts, restock alerts, booking reminders — are handed
|
|
95
|
+
* it directly. Those doors used to call core's `pluginJobHostGate()`, which
|
|
96
|
+
* answers "not locked" in any process that never registered a resolver, and
|
|
97
|
+
* the console registers none: a forced pass mailed a suspended site's
|
|
98
|
+
* customers and stamped the rows done. Asking this instead needs no
|
|
99
|
+
* registration, so it holds in whichever app serves the route.
|
|
100
|
+
*
|
|
101
|
+
* Any active lock, not only a full one, for the reason the tenant resolver
|
|
102
|
+
* gives: every scan behind it mutates, and a skipped row is picked up
|
|
103
|
+
* unchanged on the first pass after the lift.
|
|
104
|
+
*/
|
|
105
|
+
export declare function siteLockdownJobGate(): PluginJobHostGate;
|
|
76
106
|
/**
|
|
77
107
|
* The refusal a visitor-facing write route returns, or null to proceed:
|
|
78
108
|
*
|
|
@@ -71,13 +71,21 @@ import { getHostDocAdmin, getOrgForHost } from "./organizations.js";
|
|
|
71
71
|
* durable ledger exists — and a catch that locked unconditionally would take
|
|
72
72
|
* every shop on the platform offline on any transient blip, which is the
|
|
73
73
|
* deliberate posture this keeps for the default case.
|
|
74
|
-
*/ export async function getSiteLockdown(hostId, nowMs = Date.now()
|
|
74
|
+
*/ export async function getSiteLockdown(hostId, nowMs = Date.now(), /**
|
|
75
|
+
* The org and host documents, when the caller has already read them — a
|
|
76
|
+
* sender resolving its identity holds both, and outside a request scope
|
|
77
|
+
* `React.cache` dedupes nothing, so reading them again here would double
|
|
78
|
+
* the reads on every message. `undefined` for either one means "not
|
|
79
|
+
* loaded, read it"; `null` means "read, and there is none".
|
|
80
|
+
*/ loaded) {
|
|
75
81
|
if (!hostId) return null;
|
|
76
82
|
try {
|
|
77
83
|
const [platform, resolved, host] = await Promise.all([
|
|
78
84
|
getPlatformLockdown(),
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
(loaded == null ? void 0 : loaded.org) !== undefined ? Promise.resolve(loaded.org ? {
|
|
86
|
+
org: loaded.org
|
|
87
|
+
} : null) : getOrgForHost(hostId),
|
|
88
|
+
(loaded == null ? void 0 : loaded.host) !== undefined ? Promise.resolve(loaded.host) : getHostDocAdmin(hostId)
|
|
81
89
|
]);
|
|
82
90
|
const org = normalizeOrgLockdown(resolved == null ? void 0 : resolved.org);
|
|
83
91
|
const hostState = normalizeHostLockdown(host);
|
|
@@ -109,6 +117,28 @@ import { getHostDocAdmin, getOrgForHost } from "./organizations.js";
|
|
|
109
117
|
return isLockdownActive(state, nowMs) ? state : null;
|
|
110
118
|
}
|
|
111
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* The background-work gate over {@link getSiteLockdown}: ANY active lock on
|
|
122
|
+
* the site answers locked (AGL-2495, AGL-3356).
|
|
123
|
+
*
|
|
124
|
+
* One definition, two doors. The tenant's job runner registers
|
|
125
|
+
* `isLocked` as core's job resolver (`apps/tenant/utils/plugin-job-lockdown`),
|
|
126
|
+
* and the `x-cron-secret` doors that drive the same scans by hand in the
|
|
127
|
+
* CONSOLE — abandoned carts, restock alerts, booking reminders — are handed
|
|
128
|
+
* it directly. Those doors used to call core's `pluginJobHostGate()`, which
|
|
129
|
+
* answers "not locked" in any process that never registered a resolver, and
|
|
130
|
+
* the console registers none: a forced pass mailed a suspended site's
|
|
131
|
+
* customers and stamped the rows done. Asking this instead needs no
|
|
132
|
+
* registration, so it holds in whichever app serves the route.
|
|
133
|
+
*
|
|
134
|
+
* Any active lock, not only a full one, for the reason the tenant resolver
|
|
135
|
+
* gives: every scan behind it mutates, and a skipped row is picked up
|
|
136
|
+
* unchanged on the first pass after the lift.
|
|
137
|
+
*/ export function siteLockdownJobGate() {
|
|
138
|
+
return {
|
|
139
|
+
isLocked: async (hostId)=>Boolean(hostId) && await getSiteLockdown(hostId) !== null
|
|
140
|
+
};
|
|
141
|
+
}
|
|
112
142
|
/**
|
|
113
143
|
* The refusal a visitor-facing write route returns, or null to proceed:
|
|
114
144
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../libs/tenant/data/admin/src/lib/server/tenant-write-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 * The lockdown gate for VISITOR writes on a customer's live site\n * (AGL-1511) — form submissions, cart changes, checkout.\n *\n * Why this is its own chokepoint rather than the console's. The tenant\n * middleware, which is where AGL-1501 enforces, **does not match `/api`**\n * (see the matcher in apps/tenant/middleware.ts): it exists to stop CACHED\n * PAGES serving. So the site's own write endpoints have had no lockdown\n * enforcement at all — under a full org takedown the pages 503 while a form\n * POST still writes. This closes that for both modes.\n *\n * The product decision this file encodes, from the issue: a visitor-facing\n * write on a read-serving site gets a **polite inline pause, never a\n * page-level 503**. A customer's site staying up and earning is the entire\n * reason read-only mode exists instead of full lockdown, and answering their\n * visitors with an outage page would spend exactly what the mode was\n * protecting. So the refusal is a 423 with visitor copy the block renders\n * inline, and the page around it never stops rendering.\n *\n * Under a FULL lock the same 423 is returned rather than a 503, and that is\n * deliberate too: the middleware has already replaced the whole page for\n * anyone loading it, so a write arriving here is a stale tab or a script,\n * and a machine-readable refusal is more useful to both than an HTML page.\n *\n * NO staff bypass and NO user scope, matching /api/lockdown-verdict: this is\n * a public website, the caller is anonymous, and a visitor's identity plays\n * no part in whether a site accepts an order.\n */\n\nimport {\n isLockdownActive,\n lockdownBlocks,\n type LockdownIntent,\n lockdownIntentForMethod,\n type LockdownPausedSurface,\n lockdownPausedNotice,\n type LockdownState,\n normalizeHostLockdown,\n normalizeOrgLockdown,\n resolveLockdown,\n} from '@aglyn/aglyn/server'\nimport {\n getPlatformLockdown,\n heldSiteTakedown,\n lockdownJsonResponse,\n rememberSiteTakedown,\n} from './lockdown'\nimport { getHostDocAdmin, getOrgForHost } from './organizations'\n\n/**\n * The active platform/org/host lockdown for one site, or null.\n *\n * Both reads are already paid by the callers on this path — the dispatcher\n * reads the host doc for its plugin deny-list and the org doc for\n * enablement, and both getters are `React.cache`-deduped per request — so\n * the gate costs one TTL-cached platform read and nothing else.\n *\n * FAIL OPEN on any error, matching every other lockdown reader: an\n * unreachable Firestore is an outage, not a lockdown, and a shop that stops\n * taking orders because a read timed out is a worse failure than the one\n * being guarded against.\n *\n * …EXCEPT for a takedown (AGL-1881, extending AGL-1621). One class of lock\n * inverts that cost function — \"the database was down\" is not an answer to a\n * court order — and until now the ledger that carries it covered only the\n * four scopes whose lock lives in `lockdowns/*`. Org and host locks live on\n * the org/host document, so the two scopes MOST likely to be carrying a\n * legal order were the two that fell through. Every successful read now\n * records its org and host verdict, and a failed read serves back whichever\n * of them was a takedown and is still active.\n *\n * Note what is NOT done here: the catch does not fail closed on the state it\n * could not read. On a read failure `suspendedEnforcement` is exactly as\n * unreadable as everything else, which is the whole reason a separate\n * durable ledger exists — and a catch that locked unconditionally would take\n * every shop on the platform offline on any transient blip, which is the\n * deliberate posture this keeps for the default case.\n */\nexport async function getSiteLockdown(\n hostId: string,\n nowMs = Date.now(),\n): Promise<LockdownState | null> {\n if (!hostId) return null\n try {\n const [platform, resolved, host] = await Promise.all([\n getPlatformLockdown(),\n getOrgForHost(hostId),\n getHostDocAdmin(hostId),\n ])\n const org = normalizeOrgLockdown(resolved?.org as never)\n const hostState = normalizeHostLockdown(host as never)\n rememberSiteTakedown(hostId, { org, host: hostState })\n const state = resolveLockdown({ platform, org, host: hostState }, nowMs)\n return isLockdownActive(state, nowMs) ? state : null\n } catch (error) {\n console.error('[tenant-write-lockdown] verdict failed', hostId, error)\n const held = heldSiteTakedown(hostId, nowMs)\n // The shipped fail-open answer, returned by the same statement it always\n // was, for every case where nothing takedown-class was ever observed.\n if (!held.org && !held.host) return null\n // The platform read is TTL-cached and swallows its own errors (it carries\n // its own ledger entry), so asking again here costs nothing and keeps a\n // wider lock from being masked by a narrower held one.\n const platform = await getPlatformLockdown().catch(() => null)\n const state = resolveLockdown(\n { platform, org: held.org, host: held.host },\n nowMs,\n )\n return isLockdownActive(state, nowMs) ? state : null\n }\n}\n\n/**\n * The refusal a visitor-facing write route returns, or null to proceed:\n *\n * const paused = await visitorWriteRefusal({ hostId, request, surface })\n * if (paused) return paused\n *\n * `surface` picks the WORDS only (`lockdownPausedNotice`) — the checkout\n * sentence has to promise no card was charged, and no generic copy can.\n */\nexport async function visitorWriteRefusal(options: {\n hostId: string\n /** The request whose method decides read vs write. */\n request?: { method?: string } | null\n /** Overrides `request`; `write` when neither is given. */\n intent?: LockdownIntent\n surface: LockdownPausedSurface\n nowMs?: number\n}): Promise<Response | null> {\n const nowMs = options.nowMs ?? Date.now()\n const intent =\n options.intent ??\n (options.request ? lockdownIntentForMethod(options.request.method) : 'write')\n // This is a WRITE gate: reads leave before any Firestore read, so the hot\n // unauthenticated GET path pays nothing. A full lock's refusal of tenant\n // API *reads* is not attempted here and is unchanged from today — the\n // middleware owns the page surface, and a read-refusing API gate is its\n // own decision with its own blast radius (filed separately).\n if (intent === 'read') return null\n const state = await getSiteLockdown(options.hostId, nowMs)\n if (!lockdownBlocks(state, intent)) return null\n return lockdownJsonResponse(state as LockdownState, {\n notice: lockdownPausedNotice(options.surface),\n })\n}\n\n/**\n * The refusal a visitor-facing route that SERVES SITE CONTENT over `/api`\n * returns under a FULL lock, or null to proceed (AGL-2495):\n *\n * const down = await visitorContentRefusal({ hostId })\n * if (down) return down\n *\n * The gap this closes, found by the AGL-1621 drill. The tenant middleware\n * is what takes a locked site off the air, and its matcher deliberately\n * excludes `/api` — so a full org or host takedown 503s every page while an\n * API route that composes and returns screen nodes keeps handing the site's\n * content out to anyone who can name a screen. `visitorWriteRefusal` above\n * cannot answer that: it leaves before any read, by design, because it is a\n * WRITE gate on the hot unauthenticated GET path.\n *\n * FULL locks only, and that is the whole point of it being a separate\n * helper rather than a flag on the write gate. Read-only mode exists so a\n * customer's site keeps serving and earning; refusing reads there would\n * spend exactly what the mode protects. `lockdownBlocks(state, 'read')` is\n * true only when the mode is full, which is precisely the case where the\n * pages are already gone.\n *\n * Deliberately NOT applied to the whole tenant API surface. A read-refusing\n * gate on every route would take the lock notice, the verdict probe and the\n * abuse intake down with the site. This is for the routes that serve the\n * SITE ITSELF — a composed node tree — where continuing to serve is\n * continuing to publish. `serve-media-cdn.ts` made the same call for bytes\n * (AGL-1520); this is the node-tree half of it.\n *\n * Fails OPEN through `getSiteLockdown`, like every other reader here.\n */\nexport async function visitorContentRefusal(options: {\n hostId: string\n surface?: LockdownPausedSurface\n nowMs?: number\n}): Promise<Response | null> {\n const nowMs = options.nowMs ?? Date.now()\n const state = await getSiteLockdown(options.hostId, nowMs)\n if (!lockdownBlocks(state, 'read')) return null\n return lockdownJsonResponse(\n state as LockdownState,\n options.surface ? { notice: lockdownPausedNotice(options.surface) } : undefined,\n )\n}\n"],"names":["isLockdownActive","lockdownBlocks","lockdownIntentForMethod","lockdownPausedNotice","normalizeHostLockdown","normalizeOrgLockdown","resolveLockdown","getPlatformLockdown","heldSiteTakedown","lockdownJsonResponse","rememberSiteTakedown","getHostDocAdmin","getOrgForHost","getSiteLockdown","hostId","nowMs","Date","now","platform","resolved","host","Promise","all","org","hostState","state","error","console","held","catch","visitorWriteRefusal","options","intent","request","method","notice","surface","visitorContentRefusal","undefined"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GAED,SACEA,gBAAgB,EAChBC,cAAc,EAEdC,uBAAuB,EAEvBC,oBAAoB,EAEpBC,qBAAqB,EACrBC,oBAAoB,EACpBC,eAAe,QACV,sBAAqB;AAC5B,SACEC,mBAAmB,EACnBC,gBAAgB,EAChBC,oBAAoB,EACpBC,oBAAoB,QACf,gBAAY;AACnB,SAASC,eAAe,EAAEC,aAAa,QAAQ,qBAAiB;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BC,GACD,OAAO,eAAeC,gBACpBC,MAAc,EACdC,QAAQC,KAAKC,GAAG,EAAE;IAElB,IAAI,CAACH,QAAQ,OAAO;IACpB,IAAI;QACF,MAAM,CAACI,UAAUC,UAAUC,KAAK,GAAG,MAAMC,QAAQC,GAAG,CAAC;YACnDf;YACAK,cAAcE;YACdH,gBAAgBG;SACjB;QACD,MAAMS,MAAMlB,qBAAqBc,4BAAAA,SAAUI,GAAG;QAC9C,MAAMC,YAAYpB,sBAAsBgB;QACxCV,qBAAqBI,QAAQ;YAAES;YAAKH,MAAMI;QAAU;QACpD,MAAMC,QAAQnB,gBAAgB;YAAEY;YAAUK;YAAKH,MAAMI;QAAU,GAAGT;QAClE,OAAOf,iBAAiByB,OAAOV,SAASU,QAAQ;IAClD,EAAE,OAAOC,OAAO;QACdC,QAAQD,KAAK,CAAC,0CAA0CZ,QAAQY;QAChE,MAAME,OAAOpB,iBAAiBM,QAAQC;QACtC,yEAAyE;QACzE,sEAAsE;QACtE,IAAI,CAACa,KAAKL,GAAG,IAAI,CAACK,KAAKR,IAAI,EAAE,OAAO;QACpC,0EAA0E;QAC1E,wEAAwE;QACxE,uDAAuD;QACvD,MAAMF,WAAW,MAAMX,sBAAsBsB,KAAK,CAAC,IAAM;QACzD,MAAMJ,QAAQnB,gBACZ;YAAEY;YAAUK,KAAKK,KAAKL,GAAG;YAAEH,MAAMQ,KAAKR,IAAI;QAAC,GAC3CL;QAEF,OAAOf,iBAAiByB,OAAOV,SAASU,QAAQ;IAClD;AACF;AAEA;;;;;;;;CAQC,GACD,OAAO,eAAeK,oBAAoBC,OAQzC;QACeA,gBAEZA;IAFF,MAAMhB,SAAQgB,iBAAAA,QAAQhB,KAAK,YAAbgB,iBAAiBf,KAAKC,GAAG;IACvC,MAAMe,UACJD,kBAAAA,QAAQC,MAAM,YAAdD,kBACCA,QAAQE,OAAO,GAAG/B,wBAAwB6B,QAAQE,OAAO,CAACC,MAAM,IAAI;IACvE,0EAA0E;IAC1E,yEAAyE;IACzE,sEAAsE;IACtE,wEAAwE;IACxE,6DAA6D;IAC7D,IAAIF,WAAW,QAAQ,OAAO;IAC9B,MAAMP,QAAQ,MAAMZ,gBAAgBkB,QAAQjB,MAAM,EAAEC;IACpD,IAAI,CAACd,eAAewB,OAAOO,SAAS,OAAO;IAC3C,OAAOvB,qBAAqBgB,OAAwB;QAClDU,QAAQhC,qBAAqB4B,QAAQK,OAAO;IAC9C;AACF;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BC,GACD,OAAO,eAAeC,sBAAsBN,OAI3C;QACeA;IAAd,MAAMhB,SAAQgB,iBAAAA,QAAQhB,KAAK,YAAbgB,iBAAiBf,KAAKC,GAAG;IACvC,MAAMQ,QAAQ,MAAMZ,gBAAgBkB,QAAQjB,MAAM,EAAEC;IACpD,IAAI,CAACd,eAAewB,OAAO,SAAS,OAAO;IAC3C,OAAOhB,qBACLgB,OACAM,QAAQK,OAAO,GAAG;QAAED,QAAQhC,qBAAqB4B,QAAQK,OAAO;IAAE,IAAIE;AAE1E"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/tenant/data/admin/src/lib/server/tenant-write-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 * The lockdown gate for VISITOR writes on a customer's live site\n * (AGL-1511) — form submissions, cart changes, checkout.\n *\n * Why this is its own chokepoint rather than the console's. The tenant\n * middleware, which is where AGL-1501 enforces, **does not match `/api`**\n * (see the matcher in apps/tenant/middleware.ts): it exists to stop CACHED\n * PAGES serving. So the site's own write endpoints have had no lockdown\n * enforcement at all — under a full org takedown the pages 503 while a form\n * POST still writes. This closes that for both modes.\n *\n * The product decision this file encodes, from the issue: a visitor-facing\n * write on a read-serving site gets a **polite inline pause, never a\n * page-level 503**. A customer's site staying up and earning is the entire\n * reason read-only mode exists instead of full lockdown, and answering their\n * visitors with an outage page would spend exactly what the mode was\n * protecting. So the refusal is a 423 with visitor copy the block renders\n * inline, and the page around it never stops rendering.\n *\n * Under a FULL lock the same 423 is returned rather than a 503, and that is\n * deliberate too: the middleware has already replaced the whole page for\n * anyone loading it, so a write arriving here is a stale tab or a script,\n * and a machine-readable refusal is more useful to both than an HTML page.\n *\n * NO staff bypass and NO user scope, matching /api/lockdown-verdict: this is\n * a public website, the caller is anonymous, and a visitor's identity plays\n * no part in whether a site accepts an order.\n */\n\nimport {\n isLockdownActive,\n lockdownBlocks,\n type LockdownIntent,\n lockdownIntentForMethod,\n type LockdownPausedSurface,\n lockdownPausedNotice,\n type LockdownState,\n normalizeHostLockdown,\n normalizeOrgLockdown,\n type PluginJobHostGate,\n resolveLockdown,\n} from '@aglyn/aglyn/server'\nimport {\n getPlatformLockdown,\n heldSiteTakedown,\n lockdownJsonResponse,\n rememberSiteTakedown,\n} from './lockdown'\nimport { getHostDocAdmin, getOrgForHost } from './organizations'\n\n/**\n * The active platform/org/host lockdown for one site, or null.\n *\n * Both reads are already paid by the callers on this path — the dispatcher\n * reads the host doc for its plugin deny-list and the org doc for\n * enablement, and both getters are `React.cache`-deduped per request — so\n * the gate costs one TTL-cached platform read and nothing else.\n *\n * FAIL OPEN on any error, matching every other lockdown reader: an\n * unreachable Firestore is an outage, not a lockdown, and a shop that stops\n * taking orders because a read timed out is a worse failure than the one\n * being guarded against.\n *\n * …EXCEPT for a takedown (AGL-1881, extending AGL-1621). One class of lock\n * inverts that cost function — \"the database was down\" is not an answer to a\n * court order — and until now the ledger that carries it covered only the\n * four scopes whose lock lives in `lockdowns/*`. Org and host locks live on\n * the org/host document, so the two scopes MOST likely to be carrying a\n * legal order were the two that fell through. Every successful read now\n * records its org and host verdict, and a failed read serves back whichever\n * of them was a takedown and is still active.\n *\n * Note what is NOT done here: the catch does not fail closed on the state it\n * could not read. On a read failure `suspendedEnforcement` is exactly as\n * unreadable as everything else, which is the whole reason a separate\n * durable ledger exists — and a catch that locked unconditionally would take\n * every shop on the platform offline on any transient blip, which is the\n * deliberate posture this keeps for the default case.\n */\nexport async function getSiteLockdown(\n hostId: string,\n nowMs = Date.now(),\n /**\n * The org and host documents, when the caller has already read them — a\n * sender resolving its identity holds both, and outside a request scope\n * `React.cache` dedupes nothing, so reading them again here would double\n * the reads on every message. `undefined` for either one means \"not\n * loaded, read it\"; `null` means \"read, and there is none\".\n */\n loaded?: {\n org?: Record<string, unknown> | null\n host?: Record<string, unknown> | null\n },\n): Promise<LockdownState | null> {\n if (!hostId) return null\n try {\n const [platform, resolved, host] = await Promise.all([\n getPlatformLockdown(),\n loaded?.org !== undefined\n ? Promise.resolve(loaded.org ? { org: loaded.org } : null)\n : getOrgForHost(hostId),\n loaded?.host !== undefined\n ? Promise.resolve(loaded.host)\n : getHostDocAdmin(hostId),\n ])\n const org = normalizeOrgLockdown(resolved?.org as never)\n const hostState = normalizeHostLockdown(host as never)\n rememberSiteTakedown(hostId, { org, host: hostState })\n const state = resolveLockdown({ platform, org, host: hostState }, nowMs)\n return isLockdownActive(state, nowMs) ? state : null\n } catch (error) {\n console.error('[tenant-write-lockdown] verdict failed', hostId, error)\n const held = heldSiteTakedown(hostId, nowMs)\n // The shipped fail-open answer, returned by the same statement it always\n // was, for every case where nothing takedown-class was ever observed.\n if (!held.org && !held.host) return null\n // The platform read is TTL-cached and swallows its own errors (it carries\n // its own ledger entry), so asking again here costs nothing and keeps a\n // wider lock from being masked by a narrower held one.\n const platform = await getPlatformLockdown().catch(() => null)\n const state = resolveLockdown(\n { platform, org: held.org, host: held.host },\n nowMs,\n )\n return isLockdownActive(state, nowMs) ? state : null\n }\n}\n\n/**\n * The background-work gate over {@link getSiteLockdown}: ANY active lock on\n * the site answers locked (AGL-2495, AGL-3356).\n *\n * One definition, two doors. The tenant's job runner registers\n * `isLocked` as core's job resolver (`apps/tenant/utils/plugin-job-lockdown`),\n * and the `x-cron-secret` doors that drive the same scans by hand in the\n * CONSOLE — abandoned carts, restock alerts, booking reminders — are handed\n * it directly. Those doors used to call core's `pluginJobHostGate()`, which\n * answers \"not locked\" in any process that never registered a resolver, and\n * the console registers none: a forced pass mailed a suspended site's\n * customers and stamped the rows done. Asking this instead needs no\n * registration, so it holds in whichever app serves the route.\n *\n * Any active lock, not only a full one, for the reason the tenant resolver\n * gives: every scan behind it mutates, and a skipped row is picked up\n * unchanged on the first pass after the lift.\n */\nexport function siteLockdownJobGate(): PluginJobHostGate {\n return {\n isLocked: async (hostId: string) =>\n Boolean(hostId) && (await getSiteLockdown(hostId)) !== null,\n }\n}\n\n/**\n * The refusal a visitor-facing write route returns, or null to proceed:\n *\n * const paused = await visitorWriteRefusal({ hostId, request, surface })\n * if (paused) return paused\n *\n * `surface` picks the WORDS only (`lockdownPausedNotice`) — the checkout\n * sentence has to promise no card was charged, and no generic copy can.\n */\nexport async function visitorWriteRefusal(options: {\n hostId: string\n /** The request whose method decides read vs write. */\n request?: { method?: string } | null\n /** Overrides `request`; `write` when neither is given. */\n intent?: LockdownIntent\n surface: LockdownPausedSurface\n nowMs?: number\n}): Promise<Response | null> {\n const nowMs = options.nowMs ?? Date.now()\n const intent =\n options.intent ??\n (options.request ? lockdownIntentForMethod(options.request.method) : 'write')\n // This is a WRITE gate: reads leave before any Firestore read, so the hot\n // unauthenticated GET path pays nothing. A full lock's refusal of tenant\n // API *reads* is not attempted here and is unchanged from today — the\n // middleware owns the page surface, and a read-refusing API gate is its\n // own decision with its own blast radius (filed separately).\n if (intent === 'read') return null\n const state = await getSiteLockdown(options.hostId, nowMs)\n if (!lockdownBlocks(state, intent)) return null\n return lockdownJsonResponse(state as LockdownState, {\n notice: lockdownPausedNotice(options.surface),\n })\n}\n\n/**\n * The refusal a visitor-facing route that SERVES SITE CONTENT over `/api`\n * returns under a FULL lock, or null to proceed (AGL-2495):\n *\n * const down = await visitorContentRefusal({ hostId })\n * if (down) return down\n *\n * The gap this closes, found by the AGL-1621 drill. The tenant middleware\n * is what takes a locked site off the air, and its matcher deliberately\n * excludes `/api` — so a full org or host takedown 503s every page while an\n * API route that composes and returns screen nodes keeps handing the site's\n * content out to anyone who can name a screen. `visitorWriteRefusal` above\n * cannot answer that: it leaves before any read, by design, because it is a\n * WRITE gate on the hot unauthenticated GET path.\n *\n * FULL locks only, and that is the whole point of it being a separate\n * helper rather than a flag on the write gate. Read-only mode exists so a\n * customer's site keeps serving and earning; refusing reads there would\n * spend exactly what the mode protects. `lockdownBlocks(state, 'read')` is\n * true only when the mode is full, which is precisely the case where the\n * pages are already gone.\n *\n * Deliberately NOT applied to the whole tenant API surface. A read-refusing\n * gate on every route would take the lock notice, the verdict probe and the\n * abuse intake down with the site. This is for the routes that serve the\n * SITE ITSELF — a composed node tree — where continuing to serve is\n * continuing to publish. `serve-media-cdn.ts` made the same call for bytes\n * (AGL-1520); this is the node-tree half of it.\n *\n * Fails OPEN through `getSiteLockdown`, like every other reader here.\n */\nexport async function visitorContentRefusal(options: {\n hostId: string\n surface?: LockdownPausedSurface\n nowMs?: number\n}): Promise<Response | null> {\n const nowMs = options.nowMs ?? Date.now()\n const state = await getSiteLockdown(options.hostId, nowMs)\n if (!lockdownBlocks(state, 'read')) return null\n return lockdownJsonResponse(\n state as LockdownState,\n options.surface ? { notice: lockdownPausedNotice(options.surface) } : undefined,\n )\n}\n"],"names":["isLockdownActive","lockdownBlocks","lockdownIntentForMethod","lockdownPausedNotice","normalizeHostLockdown","normalizeOrgLockdown","resolveLockdown","getPlatformLockdown","heldSiteTakedown","lockdownJsonResponse","rememberSiteTakedown","getHostDocAdmin","getOrgForHost","getSiteLockdown","hostId","nowMs","Date","now","loaded","platform","resolved","host","Promise","all","org","undefined","resolve","hostState","state","error","console","held","catch","siteLockdownJobGate","isLocked","Boolean","visitorWriteRefusal","options","intent","request","method","notice","surface","visitorContentRefusal"],"mappings":"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"}
|
package/src/tenancy.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export * from './lib/server/edit-hint-token';
|
|
|
53
53
|
export * from './lib/server/email-metering';
|
|
54
54
|
export * from './lib/server/campaign-conversion-attribution';
|
|
55
55
|
export * from './lib/server/email-send-rate';
|
|
56
|
+
export * from './lib/server/email-deliverability';
|
|
56
57
|
export * from './lib/server/email-sender-reputation';
|
|
57
58
|
export * from './lib/server/erase';
|
|
58
59
|
export * from './lib/server/erase-person';
|
|
@@ -66,6 +67,8 @@ export * from './lib/server/list-members';
|
|
|
66
67
|
export * from './lib/server/lockdown';
|
|
67
68
|
export * from './lib/server/token-revocation';
|
|
68
69
|
export * from './lib/server/tenant-write-lockdown';
|
|
70
|
+
export * from './lib/server/outbound-send-review';
|
|
71
|
+
export * from './lib/server/hosted-page-review';
|
|
69
72
|
export * from './lib/server/host-email-tokens';
|
|
70
73
|
export * from './lib/server/notifications';
|
|
71
74
|
export * from './lib/server/org-billing';
|
|
@@ -80,6 +83,7 @@ export * from './lib/server/verify-email-cooldown';
|
|
|
80
83
|
export * from './lib/server/vercel-drain-signature';
|
|
81
84
|
export * from './lib/server/vercel-log-drain';
|
|
82
85
|
export * from './lib/server/visitor-write-rate-limit';
|
|
86
|
+
export * from './lib/server/card-payment-velocity';
|
|
83
87
|
export * from './lib/server/console-api-rate-limit';
|
|
84
88
|
export * from './lib/server/realm-plugins';
|
|
85
89
|
export * from './lib/server/release-flags';
|
|
@@ -97,6 +101,7 @@ export * from './lib/server/media-tombstone';
|
|
|
97
101
|
export * from './lib/server/media-variants';
|
|
98
102
|
export * from './lib/server/serve-media-cdn';
|
|
99
103
|
export * from './lib/server/serve-plugin-fetch';
|
|
104
|
+
export * from './lib/server/configured-url-fetch';
|
|
100
105
|
export * from './lib/server/sso-break-glass-owners';
|
|
101
106
|
export * from './lib/server/sso-domain-policy';
|
|
102
107
|
export * from './lib/server/sso-enforcement';
|
package/src/tenancy.js
CHANGED
|
@@ -67,6 +67,11 @@ export * from "./lib/server/email-metering.js";
|
|
|
67
67
|
// imports this barrel, so nothing has to remember to call an installer.
|
|
68
68
|
export * from "./lib/server/campaign-conversion-attribution.js";
|
|
69
69
|
export * from "./lib/server/email-send-rate.js";
|
|
70
|
+
// Side-effecting on purpose, for the same reason (AGL-3328): evaluating this
|
|
71
|
+
// module INSTALLS the deliverability preflight on `sendEmail`, so a recipient
|
|
72
|
+
// whose domain takes no mail is refused, and bulk mail behind a gateway that
|
|
73
|
+
// refused its sending domain twice is held, on every send path at once.
|
|
74
|
+
export * from "./lib/server/email-deliverability.js";
|
|
70
75
|
export * from "./lib/server/email-sender-reputation.js";
|
|
71
76
|
export * from "./lib/server/erase.js";
|
|
72
77
|
export * from "./lib/server/erase-person.js";
|
|
@@ -80,6 +85,9 @@ export * from "./lib/server/list-members.js";
|
|
|
80
85
|
export * from "./lib/server/lockdown.js";
|
|
81
86
|
export * from "./lib/server/token-revocation.js";
|
|
82
87
|
export * from "./lib/server/tenant-write-lockdown.js";
|
|
88
|
+
export * from "./lib/server/outbound-send-review.js";
|
|
89
|
+
// The same review for a published page, read where it is composed (AGL-3356).
|
|
90
|
+
export * from "./lib/server/hosted-page-review.js";
|
|
83
91
|
export * from "./lib/server/host-email-tokens.js";
|
|
84
92
|
export * from "./lib/server/notifications.js";
|
|
85
93
|
export * from "./lib/server/org-billing.js";
|
|
@@ -94,6 +102,7 @@ export * from "./lib/server/verify-email-cooldown.js";
|
|
|
94
102
|
export * from "./lib/server/vercel-drain-signature.js";
|
|
95
103
|
export * from "./lib/server/vercel-log-drain.js";
|
|
96
104
|
export * from "./lib/server/visitor-write-rate-limit.js";
|
|
105
|
+
export * from "./lib/server/card-payment-velocity.js";
|
|
97
106
|
export * from "./lib/server/console-api-rate-limit.js";
|
|
98
107
|
export * from "./lib/server/realm-plugins.js";
|
|
99
108
|
export * from "./lib/server/release-flags.js";
|
|
@@ -111,6 +120,7 @@ export * from "./lib/server/media-tombstone.js";
|
|
|
111
120
|
export * from "./lib/server/media-variants.js";
|
|
112
121
|
export * from "./lib/server/serve-media-cdn.js";
|
|
113
122
|
export * from "./lib/server/serve-plugin-fetch.js";
|
|
123
|
+
export * from "./lib/server/configured-url-fetch.js";
|
|
114
124
|
export * from "./lib/server/sso-break-glass-owners.js";
|
|
115
125
|
export * from "./lib/server/sso-domain-policy.js";
|
|
116
126
|
export * from "./lib/server/sso-enforcement.js";
|
package/src/tenancy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/tenant/data/admin/src/tenancy.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 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\nexport * from './lib/server/analytics-retention'\nexport * from './lib/server/api-http'\nexport * from './lib/server/api-keys'\nexport * from './lib/server/account-emails'\nexport * from './lib/server/auth-pools'\nexport * from './lib/server/client-error-report'\nexport * from './lib/server/connect-account-status'\nexport * from './lib/server/connect-payout-failure'\nexport * from './lib/server/stripe-account-mode'\nexport * from './lib/server/auth-handoff'\nexport * from './lib/server/console-domains'\nexport * from './lib/server/dns-probe'\nexport * from './lib/server/sending-domains'\nexport * from './lib/server/host-sending-domain'\nexport * from './lib/server/sending-domain-debt'\nexport * from './lib/server/sending-domain-recheck'\n// The hosting seam itself, so a door can ask whether this deployment is able\n// to register a name at all before it promises the caller one.\n// `workspace-domains` re-exports the pieces its own callers share with it; the\n// provider behind it is not among them.\nexport { domainProvider } from './lib/server/domain-provider'\nexport type {\n DomainProvider,\n DomainProviderId,\n DomainScope,\n} from './lib/server/domain-provider'\nexport * from './lib/server/platform-domain-names'\nexport * from './lib/server/consume-once'\nexport * from './lib/server/csp-aggregate'\nexport * from './lib/server/data-storage-gate'\nexport * from './lib/server/contact-suppression'\nexport * from './lib/server/email-suppression'\n// The double opt-in quarantine, after the module whose keying it shares and\n// whose `filterTopicSendable` is the reader that makes it a quarantine rather\n// than a stored fact.\nexport * from './lib/server/email-topic-confirmation'\nexport * from './lib/server/email-unsubscribe-link'\nexport * from './lib/server/email-flow-gate'\n// Side-effecting on purpose, for the reason `email-send-rate` below is:\n// evaluating this module INSTALLS the marketing gate on `sendEmail`, so the\n// unsubscribe header, the suppression check and the frequency ceiling reach\n// every bulk sender without a call at each server entrypoint.\nexport * from './lib/server/email-marketing-gate'\n// A consent group change (AGL-3320): the carries of the three stores above,\n// and the executor that runs a change around them.\nexport * from './lib/server/consent-group-carry'\nexport * from './lib/server/consent-group-change'\nexport * from './lib/server/sms-keywords'\nexport * from './lib/server/document-id'\nexport * from './lib/server/collection-preview-token'\nexport * from './lib/server/edit-access-authz'\nexport * from './lib/server/edit-access-token'\nexport * from './lib/server/edit-hint-token'\nexport * from './lib/server/email-metering'\n// Side-effecting on purpose (AGL-2409): evaluating this module INSTALLS the\n// platform send-rate governor on `sendEmail`. Every server surface already\n// imports this barrel, so nothing has to remember to call an installer.\nexport * from './lib/server/campaign-conversion-attribution'\nexport * from './lib/server/email-send-rate'\nexport * from './lib/server/email-sender-reputation'\nexport * from './lib/server/erase'\nexport * from './lib/server/erase-person'\nexport * from './lib/server/dynamic-list-materialize'\nexport * from './lib/server/firebase-admin'\nexport * from './lib/server/free-workspace-cap'\nexport * from './lib/server/ga4-measurement-protocol'\nexport * from './lib/server/host-memberships'\nexport * from './lib/server/host-visitor-records'\nexport * from './lib/server/list-members'\nexport * from './lib/server/lockdown'\nexport * from './lib/server/token-revocation'\nexport * from './lib/server/tenant-write-lockdown'\nexport * from './lib/server/host-email-tokens'\nexport * from './lib/server/notifications'\nexport * from './lib/server/org-billing'\nexport * from './lib/server/organizations'\nexport * from './lib/server/duplicate-activity'\nexport * from './lib/server/duplicate-resource'\nexport * from './lib/server/workspace-domains'\nexport * from './lib/server/membership-recover-throttle'\nexport * from './lib/server/password-reset-throttle'\nexport * from './lib/server/rate-limit-store'\nexport * from './lib/server/verify-email-cooldown'\nexport * from './lib/server/vercel-drain-signature'\nexport * from './lib/server/vercel-log-drain'\nexport * from './lib/server/visitor-write-rate-limit'\nexport * from './lib/server/console-api-rate-limit'\nexport * from './lib/server/realm-plugins'\nexport * from './lib/server/release-flags'\nexport * from './lib/server/resolve-people'\nexport * from './lib/server/member-photo'\nexport * from './lib/server/personal-data-export'\nexport * from './lib/server/media-delivery'\nexport * from './lib/server/media-download-tokens'\nexport * from './lib/server/media-quarantine'\nexport * from './lib/server/media-signing'\nexport * from './lib/server/media-storage-path'\nexport * from './lib/server/safe-equal'\nexport * from './lib/server/media-strong-digest'\nexport * from './lib/server/media-tombstone'\nexport * from './lib/server/media-variants'\nexport * from './lib/server/serve-media-cdn'\nexport * from './lib/server/serve-plugin-fetch'\nexport * from './lib/server/sso-break-glass-owners'\nexport * from './lib/server/sso-domain-policy'\nexport * from './lib/server/sso-enforcement'\nexport * from './lib/server/sso-provisioning'\nexport * from './lib/server/update-existing'\nexport * from './lib/server/contact-company-link'\nexport * from './lib/server/contact-email-index'\nexport * from './lib/server/contact-merge'\nexport * from './lib/server/upsert-contact'\n// The stage floor a won deal applies to its contact (AGL-2641).\nexport * from './lib/server/contact-lifecycle-floor'\nexport * from './lib/server/crm-records'\n// The `nextTaskAtMs` a contact, a company and a deal carry, recomputed from\n// their open tasks by every server-side task writer (AGL-2661).\nexport * from './lib/server/crm-next-activity'\n// Where a one-to-one email's activity row lives and how the delivery\n// webhook advances it (AGL-2615).\nexport * from './lib/server/crm-email-activity'\n// What a confirmed booking files on the CRM record — the meeting and the\n// follow-up (AGL-2660).\nexport * from './lib/server/crm-booking-activity'\n// The org's email capture token and the filing of one received message\n// on the record it was with (AGL-2657).\nexport * from './lib/server/crm-inbound-email'\n// A member's own addresses in a workspace, and the signed link that\n// confirms one (AGL-2975).\nexport * from './lib/server/member-email-aliases'\nexport * from './lib/server/user-profiles'\nexport * from './lib/server/legal-acceptance'\n// The person's decision about the platform's own product email, on their\n// document and on the operator's marketing contact (AGL-3185).\nexport * from './lib/server/platform-marketing-consent'\n"],"names":["domainProvider"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/tenant/data/admin/src/tenancy.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 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\nexport * from './lib/server/analytics-retention'\nexport * from './lib/server/api-http'\nexport * from './lib/server/api-keys'\nexport * from './lib/server/account-emails'\nexport * from './lib/server/auth-pools'\nexport * from './lib/server/client-error-report'\nexport * from './lib/server/connect-account-status'\nexport * from './lib/server/connect-payout-failure'\nexport * from './lib/server/stripe-account-mode'\nexport * from './lib/server/auth-handoff'\nexport * from './lib/server/console-domains'\nexport * from './lib/server/dns-probe'\nexport * from './lib/server/sending-domains'\nexport * from './lib/server/host-sending-domain'\nexport * from './lib/server/sending-domain-debt'\nexport * from './lib/server/sending-domain-recheck'\n// The hosting seam itself, so a door can ask whether this deployment is able\n// to register a name at all before it promises the caller one.\n// `workspace-domains` re-exports the pieces its own callers share with it; the\n// provider behind it is not among them.\nexport { domainProvider } from './lib/server/domain-provider'\nexport type {\n DomainProvider,\n DomainProviderId,\n DomainScope,\n} from './lib/server/domain-provider'\nexport * from './lib/server/platform-domain-names'\nexport * from './lib/server/consume-once'\nexport * from './lib/server/csp-aggregate'\nexport * from './lib/server/data-storage-gate'\nexport * from './lib/server/contact-suppression'\nexport * from './lib/server/email-suppression'\n// The double opt-in quarantine, after the module whose keying it shares and\n// whose `filterTopicSendable` is the reader that makes it a quarantine rather\n// than a stored fact.\nexport * from './lib/server/email-topic-confirmation'\nexport * from './lib/server/email-unsubscribe-link'\nexport * from './lib/server/email-flow-gate'\n// Side-effecting on purpose, for the reason `email-send-rate` below is:\n// evaluating this module INSTALLS the marketing gate on `sendEmail`, so the\n// unsubscribe header, the suppression check and the frequency ceiling reach\n// every bulk sender without a call at each server entrypoint.\nexport * from './lib/server/email-marketing-gate'\n// A consent group change (AGL-3320): the carries of the three stores above,\n// and the executor that runs a change around them.\nexport * from './lib/server/consent-group-carry'\nexport * from './lib/server/consent-group-change'\nexport * from './lib/server/sms-keywords'\nexport * from './lib/server/document-id'\nexport * from './lib/server/collection-preview-token'\nexport * from './lib/server/edit-access-authz'\nexport * from './lib/server/edit-access-token'\nexport * from './lib/server/edit-hint-token'\nexport * from './lib/server/email-metering'\n// Side-effecting on purpose (AGL-2409): evaluating this module INSTALLS the\n// platform send-rate governor on `sendEmail`. Every server surface already\n// imports this barrel, so nothing has to remember to call an installer.\nexport * from './lib/server/campaign-conversion-attribution'\nexport * from './lib/server/email-send-rate'\n// Side-effecting on purpose, for the same reason (AGL-3328): evaluating this\n// module INSTALLS the deliverability preflight on `sendEmail`, so a recipient\n// whose domain takes no mail is refused, and bulk mail behind a gateway that\n// refused its sending domain twice is held, on every send path at once.\nexport * from './lib/server/email-deliverability'\nexport * from './lib/server/email-sender-reputation'\nexport * from './lib/server/erase'\nexport * from './lib/server/erase-person'\nexport * from './lib/server/dynamic-list-materialize'\nexport * from './lib/server/firebase-admin'\nexport * from './lib/server/free-workspace-cap'\nexport * from './lib/server/ga4-measurement-protocol'\nexport * from './lib/server/host-memberships'\nexport * from './lib/server/host-visitor-records'\nexport * from './lib/server/list-members'\nexport * from './lib/server/lockdown'\nexport * from './lib/server/token-revocation'\nexport * from './lib/server/tenant-write-lockdown'\nexport * from './lib/server/outbound-send-review'\n// The same review for a published page, read where it is composed (AGL-3356).\nexport * from './lib/server/hosted-page-review'\nexport * from './lib/server/host-email-tokens'\nexport * from './lib/server/notifications'\nexport * from './lib/server/org-billing'\nexport * from './lib/server/organizations'\nexport * from './lib/server/duplicate-activity'\nexport * from './lib/server/duplicate-resource'\nexport * from './lib/server/workspace-domains'\nexport * from './lib/server/membership-recover-throttle'\nexport * from './lib/server/password-reset-throttle'\nexport * from './lib/server/rate-limit-store'\nexport * from './lib/server/verify-email-cooldown'\nexport * from './lib/server/vercel-drain-signature'\nexport * from './lib/server/vercel-log-drain'\nexport * from './lib/server/visitor-write-rate-limit'\nexport * from './lib/server/card-payment-velocity'\nexport * from './lib/server/console-api-rate-limit'\nexport * from './lib/server/realm-plugins'\nexport * from './lib/server/release-flags'\nexport * from './lib/server/resolve-people'\nexport * from './lib/server/member-photo'\nexport * from './lib/server/personal-data-export'\nexport * from './lib/server/media-delivery'\nexport * from './lib/server/media-download-tokens'\nexport * from './lib/server/media-quarantine'\nexport * from './lib/server/media-signing'\nexport * from './lib/server/media-storage-path'\nexport * from './lib/server/safe-equal'\nexport * from './lib/server/media-strong-digest'\nexport * from './lib/server/media-tombstone'\nexport * from './lib/server/media-variants'\nexport * from './lib/server/serve-media-cdn'\nexport * from './lib/server/serve-plugin-fetch'\nexport * from './lib/server/configured-url-fetch'\nexport * from './lib/server/sso-break-glass-owners'\nexport * from './lib/server/sso-domain-policy'\nexport * from './lib/server/sso-enforcement'\nexport * from './lib/server/sso-provisioning'\nexport * from './lib/server/update-existing'\nexport * from './lib/server/contact-company-link'\nexport * from './lib/server/contact-email-index'\nexport * from './lib/server/contact-merge'\nexport * from './lib/server/upsert-contact'\n// The stage floor a won deal applies to its contact (AGL-2641).\nexport * from './lib/server/contact-lifecycle-floor'\nexport * from './lib/server/crm-records'\n// The `nextTaskAtMs` a contact, a company and a deal carry, recomputed from\n// their open tasks by every server-side task writer (AGL-2661).\nexport * from './lib/server/crm-next-activity'\n// Where a one-to-one email's activity row lives and how the delivery\n// webhook advances it (AGL-2615).\nexport * from './lib/server/crm-email-activity'\n// What a confirmed booking files on the CRM record — the meeting and the\n// follow-up (AGL-2660).\nexport * from './lib/server/crm-booking-activity'\n// The org's email capture token and the filing of one received message\n// on the record it was with (AGL-2657).\nexport * from './lib/server/crm-inbound-email'\n// A member's own addresses in a workspace, and the signed link that\n// confirms one (AGL-2975).\nexport * from './lib/server/member-email-aliases'\nexport * from './lib/server/user-profiles'\nexport * from './lib/server/legal-acceptance'\n// The person's decision about the platform's own product email, on their\n// document and on the operator's marketing contact (AGL-3185).\nexport * from './lib/server/platform-marketing-consent'\n"],"names":["domainProvider"],"mappings":"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"}
|