@percher/shared 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/billing-test-accounts.d.ts +20 -0
  2. package/dist/billing-test-accounts.d.ts.map +1 -0
  3. package/dist/billing-test-accounts.js +32 -0
  4. package/dist/billing-test-accounts.js.map +1 -0
  5. package/dist/crash-prompt.d.ts +8 -0
  6. package/dist/crash-prompt.d.ts.map +1 -0
  7. package/dist/crash-prompt.js +10 -0
  8. package/dist/crash-prompt.js.map +1 -0
  9. package/dist/domain-name.d.ts +14 -0
  10. package/dist/domain-name.d.ts.map +1 -0
  11. package/dist/domain-name.js +14 -0
  12. package/dist/domain-name.js.map +1 -0
  13. package/dist/env-mask.d.ts +17 -0
  14. package/dist/env-mask.d.ts.map +1 -0
  15. package/dist/env-mask.js +23 -0
  16. package/dist/env-mask.js.map +1 -0
  17. package/dist/env-name.d.ts +25 -0
  18. package/dist/env-name.d.ts.map +1 -0
  19. package/dist/env-name.js +25 -0
  20. package/dist/env-name.js.map +1 -0
  21. package/dist/escape-html.d.ts +10 -0
  22. package/dist/escape-html.d.ts.map +1 -0
  23. package/dist/escape-html.js +17 -0
  24. package/dist/escape-html.js.map +1 -0
  25. package/dist/index.d.ts +7 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +7 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/legal-changes.d.ts +1 -5
  30. package/dist/legal-changes.d.ts.map +1 -1
  31. package/dist/legal-changes.js +65 -6
  32. package/dist/legal-changes.js.map +1 -1
  33. package/dist/legal.d.ts +12 -12
  34. package/dist/legal.d.ts.map +1 -1
  35. package/dist/legal.js +11 -11
  36. package/dist/legal.js.map +1 -1
  37. package/dist/platform.d.ts +2 -2
  38. package/dist/platform.js +2 -2
  39. package/dist/secure-compare.d.ts +16 -0
  40. package/dist/secure-compare.d.ts.map +1 -0
  41. package/dist/secure-compare.js +27 -0
  42. package/dist/secure-compare.js.map +1 -0
  43. package/dist/signup-invite.d.ts +1 -1
  44. package/dist/signup-invite.d.ts.map +1 -1
  45. package/dist/signup-invite.js +7 -2
  46. package/dist/signup-invite.js.map +1 -1
  47. package/dist/switches.d.ts +88 -0
  48. package/dist/switches.d.ts.map +1 -0
  49. package/dist/switches.js +231 -0
  50. package/dist/switches.js.map +1 -0
  51. package/package.json +6 -1
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Accounts allowed to buy a tier while that tier is closed to everyone else.
3
+ *
4
+ * Opening a tier through `POST /admin/plans/availability` emails every
5
+ * waitlisted address for it, so the only way to exercise a real Polar
6
+ * checkout in production before paid opening was to notify the waitlist.
7
+ * This list lets a named test account through the availability gate on
8
+ * `/billing/checkout`, and lets the dashboard unlock the button for it, with
9
+ * no change to what anyone else sees. It is read from
10
+ * `PERCHER_BILLING_TEST_ACCOUNTS` (comma-separated emails) by the API and the
11
+ * dashboard alike; the API is the enforcer, the dashboard only unlocks.
12
+ *
13
+ * Nothing else is exempted: express-request consent, product ids, quotas and
14
+ * the webhook path all apply to a test account exactly as to a customer.
15
+ */
16
+ export declare const BILLING_TEST_ACCOUNTS_ENV = "PERCHER_BILLING_TEST_ACCOUNTS";
17
+ /** Lower-cased, trimmed, de-duplicated; blanks and non-addresses dropped. */
18
+ export declare function parseBillingTestAccounts(raw: string | undefined | null): ReadonlySet<string>;
19
+ export declare function isBillingTestAccount(accounts: ReadonlySet<string> | undefined, email: string | null | undefined): boolean;
20
+ //# sourceMappingURL=billing-test-accounts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing-test-accounts.d.ts","sourceRoot":"","sources":["../src/billing-test-accounts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAO,MAAM,yBAAyB,kCAAkC,CAAC;AAEzE,6EAA6E;AAC7E,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAO5F;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,EACzC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,OAAO,CAGT"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Accounts allowed to buy a tier while that tier is closed to everyone else.
3
+ *
4
+ * Opening a tier through `POST /admin/plans/availability` emails every
5
+ * waitlisted address for it, so the only way to exercise a real Polar
6
+ * checkout in production before paid opening was to notify the waitlist.
7
+ * This list lets a named test account through the availability gate on
8
+ * `/billing/checkout`, and lets the dashboard unlock the button for it, with
9
+ * no change to what anyone else sees. It is read from
10
+ * `PERCHER_BILLING_TEST_ACCOUNTS` (comma-separated emails) by the API and the
11
+ * dashboard alike; the API is the enforcer, the dashboard only unlocks.
12
+ *
13
+ * Nothing else is exempted: express-request consent, product ids, quotas and
14
+ * the webhook path all apply to a test account exactly as to a customer.
15
+ */
16
+ export const BILLING_TEST_ACCOUNTS_ENV = "PERCHER_BILLING_TEST_ACCOUNTS";
17
+ /** Lower-cased, trimmed, de-duplicated; blanks and non-addresses dropped. */
18
+ export function parseBillingTestAccounts(raw) {
19
+ const out = new Set();
20
+ for (const part of (raw ?? "").split(",")) {
21
+ const email = part.trim().toLowerCase();
22
+ if (email.includes("@") && !email.includes(" "))
23
+ out.add(email);
24
+ }
25
+ return out;
26
+ }
27
+ export function isBillingTestAccount(accounts, email) {
28
+ if (!accounts || accounts.size === 0 || !email)
29
+ return false;
30
+ return accounts.has(email.trim().toLowerCase());
31
+ }
32
+ //# sourceMappingURL=billing-test-accounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing-test-accounts.js","sourceRoot":"","sources":["../src/billing-test-accounts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAG,+BAA+B,CAAC;AAEzE,6EAA6E;AAC7E,MAAM,UAAU,wBAAwB,CAAC,GAA8B;IACrE,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACxC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,QAAyC,EACzC,KAAgC;IAEhC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAC7D,OAAO,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A fixed request a crashed app's owner can paste into their own AI assistant.
3
+ * Percher does not send crash logs to an AI provider; the assistant reads them
4
+ * through `percher doctor`. Only the app name is interpolated, and callers pass
5
+ * a Percher app name, never log text.
6
+ */
7
+ export declare function crashAssistantPrompt(appName: string): string;
8
+ //# sourceMappingURL=crash-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crash-prompt.d.ts","sourceRoot":"","sources":["../src/crash-prompt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE5D"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * A fixed request a crashed app's owner can paste into their own AI assistant.
3
+ * Percher does not send crash logs to an AI provider; the assistant reads them
4
+ * through `percher doctor`. Only the app name is interpolated, and callers pass
5
+ * a Percher app name, never log text.
6
+ */
7
+ export function crashAssistantPrompt(appName) {
8
+ return `Run percher doctor for my Percher app "${appName}" in runtime mode and explain why it crashed.`;
9
+ }
10
+ //# sourceMappingURL=crash-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crash-prompt.js","sourceRoot":"","sources":["../src/crash-prompt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,OAAO,0CAA0C,OAAO,+CAA+C,CAAC;AAC1G,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A bare DNS hostname as Percher accepts it for custom domains: lowercase
3
+ * labels of 1 to 63 characters that neither start nor end with a hyphen, at
4
+ * least two labels, an alphabetic top-level label of two or more characters,
5
+ * and at most 253 characters in all. No protocol, no port, no trailing dot.
6
+ *
7
+ * One rule for the API's domain service and the worker's provision guard.
8
+ * The percher.toml schema (`@percher/toml`) carries the same pattern by
9
+ * value and lowercases before matching; it imports this one once a shared
10
+ * release carries it (cross-package exports move with version bumps).
11
+ * `packages/shared/test/domain-name.test.ts` fails if the two texts drift.
12
+ */
13
+ export declare const DOMAIN_RE: RegExp;
14
+ //# sourceMappingURL=domain-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-name.d.ts","sourceRoot":"","sources":["../src/domain-name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,QAA0E,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A bare DNS hostname as Percher accepts it for custom domains: lowercase
3
+ * labels of 1 to 63 characters that neither start nor end with a hyphen, at
4
+ * least two labels, an alphabetic top-level label of two or more characters,
5
+ * and at most 253 characters in all. No protocol, no port, no trailing dot.
6
+ *
7
+ * One rule for the API's domain service and the worker's provision guard.
8
+ * The percher.toml schema (`@percher/toml`) carries the same pattern by
9
+ * value and lowercases before matching; it imports this one once a shared
10
+ * release carries it (cross-package exports move with version bumps).
11
+ * `packages/shared/test/domain-name.test.ts` fails if the two texts drift.
12
+ */
13
+ export const DOMAIN_RE = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/;
14
+ //# sourceMappingURL=domain-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-name.js","sourceRoot":"","sources":["../src/domain-name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,uEAAuE,CAAC"}
@@ -0,0 +1,17 @@
1
+ /** The mask every surface shows for a hidden environment value. */
2
+ export declare const ENV_MASK = "\u2022\u2022\u2022\u2022";
3
+ /**
4
+ * Mask an environment value for display: values of eight characters or
5
+ * fewer are hidden entirely, longer ones show their first four characters.
6
+ * One rule for the API listing, the dashboard's paste preview and the CLI,
7
+ * which used to disagree (the CLI returned values of eight characters or
8
+ * fewer unmasked; the dashboard showed two characters).
9
+ */
10
+ export declare function maskEnvValue(value: string): string;
11
+ /**
12
+ * True for a string shaped like `maskEnvValue`'s output. A client that
13
+ * re-masks what the API already masked uses this to leave the API's
14
+ * four-character hint intact instead of collapsing it to the bare mask.
15
+ */
16
+ export declare function isMaskedEnvValue(value: string): boolean;
17
+ //# sourceMappingURL=env-mask.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-mask.d.ts","sourceRoot":"","sources":["../src/env-mask.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,eAAO,MAAM,QAAQ,6BAAS,CAAC;AAE/B;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEvD"}
@@ -0,0 +1,23 @@
1
+ /** The mask every surface shows for a hidden environment value. */
2
+ export const ENV_MASK = "••••";
3
+ /**
4
+ * Mask an environment value for display: values of eight characters or
5
+ * fewer are hidden entirely, longer ones show their first four characters.
6
+ * One rule for the API listing, the dashboard's paste preview and the CLI,
7
+ * which used to disagree (the CLI returned values of eight characters or
8
+ * fewer unmasked; the dashboard showed two characters).
9
+ */
10
+ export function maskEnvValue(value) {
11
+ if (value.length <= 8)
12
+ return ENV_MASK;
13
+ return `${value.slice(0, 4)}${ENV_MASK}`;
14
+ }
15
+ /**
16
+ * True for a string shaped like `maskEnvValue`'s output. A client that
17
+ * re-masks what the API already masked uses this to leave the API's
18
+ * four-character hint intact instead of collapsing it to the bare mask.
19
+ */
20
+ export function isMaskedEnvValue(value) {
21
+ return /^[^•]{0,4}••••$/.test(value);
22
+ }
23
+ //# sourceMappingURL=env-mask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-mask.js","sourceRoot":"","sources":["../src/env-mask.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IACvC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,QAAQ,EAAE,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * An environment variable NAME as Percher stores and injects it: uppercase
3
+ * letters, digits and underscores, not starting with a digit, 1 to 256
4
+ * characters. The length is part of the pattern so a copy cannot carry the
5
+ * alphabet and forget the bound.
6
+ *
7
+ * This is the API's rule (`PUT /apps/:app/env`), so it is the contract: a
8
+ * client that accepts more sends a batch the API refuses whole, and one that
9
+ * accepts less hides a name the API would have stored.
10
+ *
11
+ * The API and the dashboard import it. `@percher/toml` (`ENV_NAME_RE`) and
12
+ * `@percher/client` (`KEY_PATTERN` in env-file.ts) carry the same pattern by
13
+ * value; they import this one once a shared release carries it (cross-package
14
+ * exports move with version bumps). `packages/shared/test/env-name.test.ts`
15
+ * fails if the texts drift.
16
+ *
17
+ * Two rules are wider on purpose and are NOT copies:
18
+ * - the worker's run-payload guard also admits lowercase, because the platform
19
+ * injects `http_proxy`/`https_proxy`/`no_proxy` and because a name stored
20
+ * before the API required uppercase must still reach its container;
21
+ * - `isEnvKey` in `@percher/core` validates names the API REPORTS, and the
22
+ * source scanner reports references in whatever case the source wrote.
23
+ */
24
+ export declare const ENV_NAME_RE: RegExp;
25
+ //# sourceMappingURL=env-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-name.d.ts","sourceRoot":"","sources":["../src/env-name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,WAAW,QAA6B,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * An environment variable NAME as Percher stores and injects it: uppercase
3
+ * letters, digits and underscores, not starting with a digit, 1 to 256
4
+ * characters. The length is part of the pattern so a copy cannot carry the
5
+ * alphabet and forget the bound.
6
+ *
7
+ * This is the API's rule (`PUT /apps/:app/env`), so it is the contract: a
8
+ * client that accepts more sends a batch the API refuses whole, and one that
9
+ * accepts less hides a name the API would have stored.
10
+ *
11
+ * The API and the dashboard import it. `@percher/toml` (`ENV_NAME_RE`) and
12
+ * `@percher/client` (`KEY_PATTERN` in env-file.ts) carry the same pattern by
13
+ * value; they import this one once a shared release carries it (cross-package
14
+ * exports move with version bumps). `packages/shared/test/env-name.test.ts`
15
+ * fails if the texts drift.
16
+ *
17
+ * Two rules are wider on purpose and are NOT copies:
18
+ * - the worker's run-payload guard also admits lowercase, because the platform
19
+ * injects `http_proxy`/`https_proxy`/`no_proxy` and because a name stored
20
+ * before the API required uppercase must still reach its container;
21
+ * - `isEnvKey` in `@percher/core` validates names the API REPORTS, and the
22
+ * source scanner reports references in whatever case the source wrote.
23
+ */
24
+ export const ENV_NAME_RE = /^[A-Z_][A-Z0-9_]{0,255}$/;
25
+ //# sourceMappingURL=env-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-name.js","sourceRoot":"","sources":["../src/env-name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,0BAA0B,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Escape text for interpolation into HTML (or XML) markup: the five
3
+ * characters that can end a text node or an attribute value. One copy for
4
+ * every process; the six hand-rolled variants it replaces disagreed on
5
+ * whether quotes were escaped, which is the difference between a name that
6
+ * is safe in a text node and one that is also safe inside an attribute.
7
+ * Pure string work, so the barrel can carry it into browser bundles.
8
+ */
9
+ export declare function escapeHtml(value: string): string;
10
+ //# sourceMappingURL=escape-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escape-html.d.ts","sourceRoot":"","sources":["../src/escape-html.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOhD"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Escape text for interpolation into HTML (or XML) markup: the five
3
+ * characters that can end a text node or an attribute value. One copy for
4
+ * every process; the six hand-rolled variants it replaces disagreed on
5
+ * whether quotes were escaped, which is the difference between a name that
6
+ * is safe in a text node and one that is also safe inside an attribute.
7
+ * Pure string work, so the barrel can carry it into browser bundles.
8
+ */
9
+ export function escapeHtml(value) {
10
+ return value
11
+ .replace(/&/g, "&amp;")
12
+ .replace(/</g, "&lt;")
13
+ .replace(/>/g, "&gt;")
14
+ .replace(/"/g, "&quot;")
15
+ .replace(/'/g, "&#39;");
16
+ }
17
+ //# sourceMappingURL=escape-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escape-html.js","sourceRoot":"","sources":["../src/escape-html.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  export { APP_NAME_RE } from "./app-name.js";
2
+ export { BILLING_TEST_ACCOUNTS_ENV, isBillingTestAccount, parseBillingTestAccounts, } from "./billing-test-accounts.js";
2
3
  export { BRAND, ICON_COLOURS, type IconColourKey, iconColourHex } from "./brand.js";
3
4
  export { CLIENT_IP_ATTESTATION_MAX_SKEW_MS, CLIENT_IP_ATTESTATION_VERSION, CLIENT_IP_HEADER, CLIENT_IP_MAX_LENGTH, CLIENT_IP_PROOF_HEADER, type ClientIpAttestationParts, clientIpAttestationPayload, formatClientIpProof, parseClientIpProof, } from "./client-ip-attestation.js";
5
+ export { crashAssistantPrompt } from "./crash-prompt.js";
6
+ export { DOMAIN_RE } from "./domain-name.js";
7
+ export { ENV_MASK, isMaskedEnvValue, maskEnvValue } from "./env-mask.js";
8
+ export { ENV_NAME_RE } from "./env-name.js";
9
+ export { escapeHtml } from "./escape-html.js";
4
10
  export { INTERNAL_SIG_HEADER, INTERNAL_SIG_MAX_SKEW_MS, INTERNAL_SIG_VERSION, INTERNAL_TS_HEADER, type InternalSigParts, internalSigPayload, } from "./internal-sig.js";
5
11
  export { CURRENT_TERMS_VERSION, LEGAL_DOCUMENT_HASHES, LEGAL_DOCUMENT_LAST_UPDATED, LEGAL_DOCUMENT_VERSIONS, type TermsAcceptanceEvidence, } from "./legal.js";
6
12
  export { canonicalLegalChangeJson, compareVersions, declaredVersion, LEGAL_CHANGE_ID_PATTERN, LEGAL_CHANGES, LEGAL_VERSION_PATTERN, type LegalChange, type LegalChangeDocument, type LegalChangeEnforcement, type LegalChangeReason, type LegalDocumentKey, MATERIAL_CHANGE_NOTICE_MS, openMaterialChanges, pendingAcknowledgement, SIGNUP_DISCLOSURE_HEADER, } from "./legal-changes.js";
@@ -12,6 +18,7 @@ export { DEFAULT_DOMAIN_SUFFIX, DEFAULT_MCP_HTTP_PORT, DEFAULT_POCKETBASE_IMAGE,
12
18
  export { canonicalInjectedKey, isPercherInjected, PERCHER_INJECTED_ENV_KEYS, } from "./platform-env.js";
13
19
  export { DEFAULT_NODE_VERSION_LABEL, DEFAULT_NODE_VERSION_MAJOR } from "./runtime.js";
14
20
  export { normalizeSignupInviteCode, SIGNUP_INVITE_CODE_ALPHABET, SIGNUP_INVITE_CODE_LENGTH, SIGNUP_INVITE_CODE_PREFIX, SIGNUP_INVITE_HEADER, } from "./signup-invite.js";
21
+ export { assertValidSwitches, type BooleanSwitch, type EnumSwitch, type PresenceSwitch, reportSwitches, SWITCH_BY_NAME, SWITCHES, type SwitchReader, type SwitchReport, type SwitchSpec, type SwitchState, switchEnabled, switchState, switchValue, } from "./switches.js";
15
22
  export { BUN_MAX_IDLE_TIMEOUT_SECONDS, HTTP_IDLE_TIMEOUT_SECONDS, type HttpIdleTimeoutSurface, TIMEOUTS, type TimeoutKey, } from "./timeouts.js";
16
23
  export { WAITLIST_THROTTLE_WINDOW_MS } from "./waitlist.js";
17
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EACL,iCAAiC,EACjC,6BAA6B,EAC7B,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,wBAAwB,EAC7B,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,uBAAuB,GAC7B,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,wBAAwB,EACxB,eAAe,EACf,eAAe,EACf,uBAAuB,EACvB,aAAa,EACb,qBAAqB,EACrB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,yBAAyB,EACzB,mBAAmB,EACnB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,iCAAiC,EACjC,iBAAiB,EACjB,sBAAsB,EACtB,wBAAwB,EACxB,sBAAsB,EACtB,8BAA8B,EAC9B,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EACL,yCAAyC,EACzC,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,yBAAyB,EACzB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EACzB,KAAK,sBAAsB,EAC3B,QAAQ,EACR,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,12 @@
1
1
  export { APP_NAME_RE } from "./app-name.js";
2
+ export { BILLING_TEST_ACCOUNTS_ENV, isBillingTestAccount, parseBillingTestAccounts, } from "./billing-test-accounts.js";
2
3
  export { BRAND, ICON_COLOURS, iconColourHex } from "./brand.js";
3
4
  export { CLIENT_IP_ATTESTATION_MAX_SKEW_MS, CLIENT_IP_ATTESTATION_VERSION, CLIENT_IP_HEADER, CLIENT_IP_MAX_LENGTH, CLIENT_IP_PROOF_HEADER, clientIpAttestationPayload, formatClientIpProof, parseClientIpProof, } from "./client-ip-attestation.js";
5
+ export { crashAssistantPrompt } from "./crash-prompt.js";
6
+ export { DOMAIN_RE } from "./domain-name.js";
7
+ export { ENV_MASK, isMaskedEnvValue, maskEnvValue } from "./env-mask.js";
8
+ export { ENV_NAME_RE } from "./env-name.js";
9
+ export { escapeHtml } from "./escape-html.js";
4
10
  export { INTERNAL_SIG_HEADER, INTERNAL_SIG_MAX_SKEW_MS, INTERNAL_SIG_VERSION, INTERNAL_TS_HEADER, internalSigPayload, } from "./internal-sig.js";
5
11
  export { CURRENT_TERMS_VERSION, LEGAL_DOCUMENT_HASHES, LEGAL_DOCUMENT_LAST_UPDATED, LEGAL_DOCUMENT_VERSIONS, } from "./legal.js";
6
12
  export { canonicalLegalChangeJson, compareVersions, declaredVersion, LEGAL_CHANGE_ID_PATTERN, LEGAL_CHANGES, LEGAL_VERSION_PATTERN, MATERIAL_CHANGE_NOTICE_MS, openMaterialChanges, pendingAcknowledgement, SIGNUP_DISCLOSURE_HEADER, } from "./legal-changes.js";
@@ -12,6 +18,7 @@ export { DEFAULT_DOMAIN_SUFFIX, DEFAULT_MCP_HTTP_PORT, DEFAULT_POCKETBASE_IMAGE,
12
18
  export { canonicalInjectedKey, isPercherInjected, PERCHER_INJECTED_ENV_KEYS, } from "./platform-env.js";
13
19
  export { DEFAULT_NODE_VERSION_LABEL, DEFAULT_NODE_VERSION_MAJOR } from "./runtime.js";
14
20
  export { normalizeSignupInviteCode, SIGNUP_INVITE_CODE_ALPHABET, SIGNUP_INVITE_CODE_LENGTH, SIGNUP_INVITE_CODE_PREFIX, SIGNUP_INVITE_HEADER, } from "./signup-invite.js";
21
+ export { assertValidSwitches, reportSwitches, SWITCH_BY_NAME, SWITCHES, switchEnabled, switchState, switchValue, } from "./switches.js";
15
22
  export { BUN_MAX_IDLE_TIMEOUT_SECONDS, HTTP_IDLE_TIMEOUT_SECONDS, TIMEOUTS, } from "./timeouts.js";
16
23
  export { WAITLIST_THROTTLE_WINDOW_MS } from "./waitlist.js";
17
24
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAsB,aAAa,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EACL,iCAAiC,EACjC,6BAA6B,EAC7B,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EAEtB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAElB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,2BAA2B,EAC3B,uBAAuB,GAExB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,wBAAwB,EACxB,eAAe,EACf,eAAe,EACf,uBAAuB,EACvB,aAAa,EACb,qBAAqB,EAMrB,yBAAyB,EACzB,mBAAmB,EACnB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,iCAAiC,EACjC,iBAAiB,EACjB,sBAAsB,EACtB,wBAAwB,EACxB,sBAAsB,EACtB,8BAA8B,EAC9B,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EACL,yCAAyC,EACzC,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,yBAAyB,EACzB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAEzB,QAAQ,GAET,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EACL,yBAAyB,EACzB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAsB,aAAa,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EACL,iCAAiC,EACjC,6BAA6B,EAC7B,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EAEtB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAElB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,2BAA2B,EAC3B,uBAAuB,GAExB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,wBAAwB,EACxB,eAAe,EACf,eAAe,EACf,uBAAuB,EACvB,aAAa,EACb,qBAAqB,EAMrB,yBAAyB,EACzB,mBAAmB,EACnB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,iCAAiC,EACjC,iBAAiB,EACjB,sBAAsB,EACtB,wBAAwB,EACxB,sBAAsB,EACtB,8BAA8B,EAC9B,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EACL,yCAAyC,EACzC,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,yBAAyB,EACzB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,mBAAmB,EAInB,cAAc,EACd,cAAc,EACd,QAAQ,EAKR,aAAa,EACb,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAEzB,QAAQ,GAET,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC"}
@@ -63,11 +63,7 @@ export interface LegalChange {
63
63
  /** Set when the same change also modifies the Service itself (2019/770 Art. 19). */
64
64
  modifiesService?: boolean;
65
65
  }
66
- /**
67
- * Newest last. Empty because version 1.0 is the first publication under
68
- * Kaizensu AB: there is no earlier version to have changed from, so the chain
69
- * starts here rather than being backfilled with a notice nobody was owed.
70
- */
66
+ /** Newest last. Editorial corrections record the published document history. */
71
67
  export declare const LEGAL_CHANGES: readonly LegalChange[];
72
68
  /**
73
69
  * Header carrying the change ids the signup form actually rendered.
@@ -1 +1 @@
1
- {"version":3,"file":"legal-changes.d.ts","sourceRoot":"","sources":["../src/legal-changes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAElD;;;;;;;;;;;;;;;;;GAiBG;AAEH,sFAAsF;AACtF,MAAM,MAAM,iBAAiB,GACzB,kBAAkB,GAClB,UAAU,GACV,kBAAkB,GAClB,gBAAgB,GAChB,iBAAiB,GACjB,eAAe,CAAC;AAEpB;;;;;;;;;;GAUG;AACH,MAAM,MAAM,sBAAsB,GAAG,aAAa,GAAG,sBAAsB,GAAG,kBAAkB,CAAC;AAEjG,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,uBAAuB,CAAC;AAEpE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,gBAAgB,CAAC;IACtB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,kGAAkG;IAClG,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,WAAW;IAC1B,2FAA2F;IAC3F,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,WAAW,EAAE,UAAU,GAAG,WAAW,CAAC;IACtC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,WAAW,EAAE,sBAAsB,CAAC;IACpC,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C;;;OAGG;IACH,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,oFAAoF;IACpF,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAAO,CAAC;AAExD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AAEtE,gEAAgE;AAChE,eAAO,MAAM,yBAAyB,QAA2B,CAAC;AAElE,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,QAAiD,CAAC;AAEtF,2FAA2F;AAC3F,eAAO,MAAM,qBAAqB,QAAyB,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAgBpE;AAED,6EAA6E;AAC7E,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,SAAS,WAAW,EAAkB,GAC9C,WAAW,EAAE,CAIf;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,gBAAgB,EACrB,OAAO,GAAE,SAAS,WAAW,EAAkB,GAC9C,MAAM,CAMR;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA6BnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,oBAAoB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,SAAS,WAAW,EAAkB,GAC9C,WAAW,GAAG,IAAI,CAiBpB"}
1
+ {"version":3,"file":"legal-changes.d.ts","sourceRoot":"","sources":["../src/legal-changes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAElD;;;;;;;;;;;;;;;;;GAiBG;AAEH,sFAAsF;AACtF,MAAM,MAAM,iBAAiB,GACzB,kBAAkB,GAClB,UAAU,GACV,kBAAkB,GAClB,gBAAgB,GAChB,iBAAiB,GACjB,eAAe,CAAC;AAEpB;;;;;;;;;;GAUG;AACH,MAAM,MAAM,sBAAsB,GAAG,aAAa,GAAG,sBAAsB,GAAG,kBAAkB,CAAC;AAEjG,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,uBAAuB,CAAC;AAEpE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,gBAAgB,CAAC;IACtB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,kGAAkG;IAClG,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,WAAW;IAC1B,2FAA2F;IAC3F,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,WAAW,EAAE,UAAU,GAAG,WAAW,CAAC;IACtC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,WAAW,EAAE,sBAAsB,CAAC;IACpC,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C;;;OAGG;IACH,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,oFAAoF;IACpF,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,gFAAgF;AAChF,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EA+D/C,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AAEtE,gEAAgE;AAChE,eAAO,MAAM,yBAAyB,QAA2B,CAAC;AAElE,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,QAAiD,CAAC;AAEtF,2FAA2F;AAC3F,eAAO,MAAM,qBAAqB,QAAyB,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAgBpE;AAED,6EAA6E;AAC7E,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,SAAS,WAAW,EAAkB,GAC9C,WAAW,EAAE,CAIf;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,gBAAgB,EACrB,OAAO,GAAE,SAAS,WAAW,EAAkB,GAC9C,MAAM,CAMR;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA6BnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,oBAAoB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,SAAS,WAAW,EAAkB,GAC9C,WAAW,GAAG,IAAI,CAiBpB"}
@@ -1,10 +1,69 @@
1
1
  import { LEGAL_DOCUMENT_VERSIONS } from "./legal.js";
2
- /**
3
- * Newest last. Empty because version 1.0 is the first publication under
4
- * Kaizensu AB: there is no earlier version to have changed from, so the chain
5
- * starts here rather than being backfilled with a notice nobody was owed.
6
- */
7
- export const LEGAL_CHANGES = [];
2
+ /** Newest last. Editorial corrections record the published document history. */
3
+ export const LEGAL_CHANGES = [
4
+ {
5
+ id: "2026-09-21-cookie-inventory-correction",
6
+ materiality: "editorial",
7
+ reason: "clarification",
8
+ enforcement: "notice_only",
9
+ announceAt: "2026-09-21T00:00:00.000Z",
10
+ effectiveAt: "2026-09-21T00:00:00.000Z",
11
+ documents: [{ key: "cookies", from: "1.0", to: "1.0.1" }],
12
+ summary: {
13
+ en: "Removed an unused social sign-in cookie from the cookie inventory. Percher accounts use email and password; the GitHub App connection cookie remains listed.",
14
+ sv: "Tog bort en oanvänd cookie för social inloggning från cookieförteckningen. Percher-konton använder e-post och lösenord; cookien för anslutning av GitHub App finns kvar.",
15
+ },
16
+ },
17
+ {
18
+ id: "2026-09-21-badge-storage-removal",
19
+ materiality: "editorial",
20
+ reason: "clarification",
21
+ enforcement: "notice_only",
22
+ announceAt: "2026-09-21T00:00:00.000Z",
23
+ effectiveAt: "2026-09-21T00:00:00.000Z",
24
+ documents: [{ key: "cookies", from: "1.0.1", to: "1.0.2" }],
25
+ summary: {
26
+ en: "Removed the badge preference from the storage inventory. The Percher badge is now an icon link and no longer stores a collapse preference.",
27
+ sv: "Tog bort emblemets inställning från lagringsförteckningen. Percher-emblemet är nu en ikonlänk och sparar inte längre om det är hopfällt.",
28
+ },
29
+ },
30
+ {
31
+ id: "2026-09-22-precision-corrections",
32
+ materiality: "editorial",
33
+ reason: "clarification",
34
+ enforcement: "notice_only",
35
+ announceAt: "2026-09-22T00:00:00.000Z",
36
+ effectiveAt: "2026-09-22T00:00:00.000Z",
37
+ documents: [
38
+ { key: "terms", from: "1.0", to: "1.0.1" },
39
+ { key: "aup", from: "1.0", to: "1.0.1" },
40
+ { key: "privacy", from: "1.0", to: "1.0.1" },
41
+ { key: "cookies", from: "1.0.2", to: "1.0.3" },
42
+ { key: "subprocessors", from: "1.0", to: "1.0.1" },
43
+ ],
44
+ summary: {
45
+ en: "Corrections and shortening, no change to rights or obligations. The Privacy Policy now states the retention periods the Service applies to abuse reports and support cases. The Cookie Policy names the app-access cookies as set (__Host- prefix) and drops text repeated from the Privacy Policy. The AUP and Terms drop rules stated twice, the ARN filing fee and the AUP contact section; the language rule now sits in each document's header. The AUP keeps the rule against scraping the Service and restates the sanctions and export-control law that already applies.",
46
+ sv: "Rättelser och förkortning, utan ändring av rättigheter eller skyldigheter. Integritetspolicyn anger nu de lagringstider som Tjänsten tillämpar för missbruksanmälningar och supportärenden. Cookiepolicyn anger appåtkomstcookierna som de sätts (prefixet __Host-) och tar bort text som upprepas från Integritetspolicyn. AUP:n och Villkoren tar bort regler som angavs två gånger, ARN:s anmälningsavgift och AUP:ns kontaktavsnitt; språkregeln finns nu i varje dokuments sidhuvud. AUP:n behåller regeln mot att skrapa Tjänsten och återger den sanktions- och exportkontrollagstiftning som redan gäller.",
47
+ },
48
+ },
49
+ {
50
+ id: "2026-09-24-crash-diagnostics-without-external-ai",
51
+ materiality: "editorial",
52
+ reason: "provider_change",
53
+ enforcement: "notice_only",
54
+ announceAt: "2026-09-24T00:00:00.000Z",
55
+ effectiveAt: "2026-09-24T00:00:00.000Z",
56
+ documents: [
57
+ { key: "terms", from: "1.0.1", to: "1.0.2" },
58
+ { key: "privacy", from: "1.0.1", to: "1.0.2" },
59
+ { key: "subprocessors", from: "1.0.1", to: "1.0.2" },
60
+ ],
61
+ summary: {
62
+ en: "Crash Diagnostics now come from fixed rules within Percher, and crash logs are not sent to an external AI provider. The option of external AI crash analysis, which was switched off, is removed, and its provider is no longer listed. Section 3.3 explicitly refers to Section 9 and mandatory law for liability. No new processing and no change to your rights or obligations.",
63
+ sv: "Kraschdiagnostik tas nu fram med fasta regler inom Percher, och kraschloggar skickas inte till någon extern AI-leverantör. Möjligheten till extern AI-kraschanalys, som var avstängd, tas bort och dess leverantör listas inte längre. Avsnitt 3.3 hänvisar uttryckligen till avsnitt 9 och tvingande lag för ansvar. Ingen ny behandling och ingen ändring av dina rättigheter eller skyldigheter.",
64
+ },
65
+ },
66
+ ];
8
67
  /**
9
68
  * Header carrying the change ids the signup form actually rendered.
10
69
  *
@@ -1 +1 @@
1
- {"version":3,"file":"legal-changes.js","sourceRoot":"","sources":["../src/legal-changes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AA2ElD;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAA2B,EAAE,CAAC;AAExD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,6BAA6B,CAAC;AAEtE,gEAAgE;AAChE,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAElE,iFAAiF;AACjF,MAAM,CAAC,MAAM,uBAAuB,GAAG,8CAA8C,CAAC;AAEtF,2FAA2F;AAC3F,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAE5D;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAmB;IAC1D,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC7C,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,EAAE,EAAE,QAAQ,CAAC,EAAE;SAChB,CAAC,CAAC;QACH,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,eAAe,EAAE,MAAM,CAAC,eAAe,KAAK,IAAI;QAChD,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE;KAC1D,CAAC,CAAC;AACL,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,OAAO,GAA2B,aAAa;IAE/C,OAAO,OAAO,CAAC,MAAM,CACnB,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,KAAK,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,GAAG,CACtF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAqB,EACrB,OAAO,GAA2B,aAAa;IAE/C,KAAK,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;QAC9E,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC,EAAE,CAAC;IACnC,CAAC;IACD,OAAO,uBAAuB,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,KAAa;IACzD,yEAAyE;IACzE,2EAA2E;IAC3E,0EAA0E;IAC1E,8EAA8E;IAC9E,0EAA0E;IAC1E,gDAAgD;IAChD,MAAM,KAAK,GAAG,CAAC,KAAa,EAAmC,EAAE;QAC/D,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACpD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,SAAS,GAAG,CAAC,IAAwB,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACvF,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC,CAAC;IACF,4EAA4E;IAC5E,uDAAuD;IACvD,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE;QAC7C,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;YAAE,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC,CAAC;IACF,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IACtB,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IACvB,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACjB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;QAC3D,IAAI,UAAU,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;IAC1C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CACpC,oBAA+C,EAC/C,GAAW,EACX,OAAO,GAA2B,aAAa;IAE/C,IAAI,CAAC,oBAAoB;QAAE,OAAO,IAAI,CAAC;IACvC,KAAK,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC5D,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,MAAM,EAAE,WAAW,KAAK,UAAU;YAAE,SAAS;QACjD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,GAAG;YAAE,SAAS;QACnD,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,OAAO,CAAC,CAAC;QACtE,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,yEAAyE;QACzE,uEAAuE;QACvE,qEAAqE;QACrE,wEAAwE;QACxE,0EAA0E;QAC1E,4BAA4B;QAC5B,OAAO,eAAe,CAAC,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"legal-changes.js","sourceRoot":"","sources":["../src/legal-changes.ts"],"names":[],"mappings":"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"}
package/dist/legal.d.ts CHANGED
@@ -12,12 +12,12 @@
12
12
  * re-acceptance.
13
13
  */
14
14
  export declare const LEGAL_DOCUMENT_VERSIONS: {
15
- readonly terms: "1.0";
16
- readonly aup: "1.0";
17
- readonly privacy: "1.0";
18
- readonly cookies: "1.0";
15
+ readonly terms: "1.0.2";
16
+ readonly aup: "1.0.1";
17
+ readonly privacy: "1.0.2";
18
+ readonly cookies: "1.0.3";
19
19
  readonly dpa: "1.0";
20
- readonly subprocessors: "1.0";
20
+ readonly subprocessors: "1.0.2";
21
21
  readonly dataPortability: "1.0";
22
22
  };
23
23
  /**
@@ -39,18 +39,18 @@ export declare const LEGAL_DOCUMENT_VERSIONS: {
39
39
  * belongs to.
40
40
  */
41
41
  export declare const LEGAL_DOCUMENT_HASHES: {
42
- readonly terms: "d412c9e85d7fefa5e3595b47aaea67a5d9f495955e458b2d0b4f43c9215317ce";
43
- readonly aup: "138ce3bdd9d244a4f31c98955b3c9d59920f32c056608f1135dc8393769a761f";
44
- readonly privacy: "186910f4f4825d3ac3bbc3340e7bf4babccea33f8b4166a10c892a7012cff175";
45
- readonly cookies: "9c8250a4ea2fbf701d04cfb145d466ff8ba410e6da92433950f119952ba16bf0";
42
+ readonly terms: "dd1775a732d830cbc4fde88662ea557322cc2745a6afbe3b8bf9c497a97c2fc4";
43
+ readonly aup: "355feaa5c38bc2fb84ef66de73f16f2c7fcd25216b30399c451c263aa5c16597";
44
+ readonly privacy: "c4d5787c38eb8c0587dd92273c919037c88f8b712ea9f945a8051b50c9c99cf3";
45
+ readonly cookies: "aeb4d1c796e95077b88c5f5e5d11d5d9f43d6f5dae7e93bdfb1542162e9c9059";
46
46
  readonly dpa: "4c97fd36c886a113477f3eb2c2c0a9b5e03820ec624439906c938bbd40f7a0fb";
47
- readonly subprocessors: "e7380f2d604814e1f06f44d8c4afcb34143c1c7994dfecdcec4cf1bbc8810363";
47
+ readonly subprocessors: "d45a3dc82df6aa5ba270a3066f544225848bcc8061934cfc910355f84c50f9a4";
48
48
  readonly dataPortability: "27a7d3ec0175af8f3f1c67db1a65bf01f74d5139b44d9134caef5dd8a924d775";
49
49
  };
50
50
  /** Version of the canonical English Terms presented during account acceptance. */
51
- export declare const CURRENT_TERMS_VERSION: "1.0";
51
+ export declare const CURRENT_TERMS_VERSION: "1.0.2";
52
52
  /** The "Last updated" date shared by the current revision of the documents. */
53
- export declare const LEGAL_DOCUMENT_LAST_UPDATED = "10 September 2026";
53
+ export declare const LEGAL_DOCUMENT_LAST_UPDATED = "24 September 2026";
54
54
  export interface TermsAcceptanceEvidence {
55
55
  version?: string;
56
56
  language?: "en" | "sv";
@@ -1 +1 @@
1
- {"version":3,"file":"legal.d.ts","sourceRoot":"","sources":["../src/legal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB;aAClC,KAAK,EAAE,KAAK;aACZ,GAAG,EAAE,KAAK;aACV,OAAO,EAAE,KAAK;aACd,OAAO,EAAE,KAAK;aACd,GAAG,EAAE,KAAK;aACV,aAAa,EAAE,KAAK;aACpB,eAAe,EAAE,KAAK;CACd,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,qBAAqB;aAChC,KAAK,EAAE,kEAAkE;aACzE,GAAG,EAAE,kEAAkE;aACvE,OAAO,EAAE,kEAAkE;aAC3E,OAAO,EAAE,kEAAkE;aAC3E,GAAG,EAAE,kEAAkE;aACvE,aAAa,EAAE,kEAAkE;aACjF,eAAe,EAAE,kEAAkE;CAC3E,CAAC;AAEX,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,OAAgC,CAAC;AAEnE,+EAA+E;AAC/E,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAE/D,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACxB"}
1
+ {"version":3,"file":"legal.d.ts","sourceRoot":"","sources":["../src/legal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB;aAClC,KAAK,EAAE,OAAO;aACd,GAAG,EAAE,OAAO;aACZ,OAAO,EAAE,OAAO;aAChB,OAAO,EAAE,OAAO;aAChB,GAAG,EAAE,KAAK;aACV,aAAa,EAAE,OAAO;aACtB,eAAe,EAAE,KAAK;CACd,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,qBAAqB;aAChC,KAAK,EAAE,kEAAkE;aACzE,GAAG,EAAE,kEAAkE;aACvE,OAAO,EAAE,kEAAkE;aAC3E,OAAO,EAAE,kEAAkE;aAC3E,GAAG,EAAE,kEAAkE;aACvE,aAAa,EAAE,kEAAkE;aACjF,eAAe,EAAE,kEAAkE;CAC3E,CAAC;AAEX,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,SAAgC,CAAC;AAEnE,+EAA+E;AAC/E,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAE/D,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACxB"}
package/dist/legal.js CHANGED
@@ -12,12 +12,12 @@
12
12
  * re-acceptance.
13
13
  */
14
14
  export const LEGAL_DOCUMENT_VERSIONS = {
15
- terms: "1.0",
16
- aup: "1.0",
17
- privacy: "1.0",
18
- cookies: "1.0",
15
+ terms: "1.0.2",
16
+ aup: "1.0.1",
17
+ privacy: "1.0.2",
18
+ cookies: "1.0.3",
19
19
  dpa: "1.0",
20
- subprocessors: "1.0",
20
+ subprocessors: "1.0.2",
21
21
  dataPortability: "1.0",
22
22
  };
23
23
  /**
@@ -39,16 +39,16 @@ export const LEGAL_DOCUMENT_VERSIONS = {
39
39
  * belongs to.
40
40
  */
41
41
  export const LEGAL_DOCUMENT_HASHES = {
42
- terms: "d412c9e85d7fefa5e3595b47aaea67a5d9f495955e458b2d0b4f43c9215317ce",
43
- aup: "138ce3bdd9d244a4f31c98955b3c9d59920f32c056608f1135dc8393769a761f",
44
- privacy: "186910f4f4825d3ac3bbc3340e7bf4babccea33f8b4166a10c892a7012cff175",
45
- cookies: "9c8250a4ea2fbf701d04cfb145d466ff8ba410e6da92433950f119952ba16bf0",
42
+ terms: "dd1775a732d830cbc4fde88662ea557322cc2745a6afbe3b8bf9c497a97c2fc4",
43
+ aup: "355feaa5c38bc2fb84ef66de73f16f2c7fcd25216b30399c451c263aa5c16597",
44
+ privacy: "c4d5787c38eb8c0587dd92273c919037c88f8b712ea9f945a8051b50c9c99cf3",
45
+ cookies: "aeb4d1c796e95077b88c5f5e5d11d5d9f43d6f5dae7e93bdfb1542162e9c9059",
46
46
  dpa: "4c97fd36c886a113477f3eb2c2c0a9b5e03820ec624439906c938bbd40f7a0fb",
47
- subprocessors: "e7380f2d604814e1f06f44d8c4afcb34143c1c7994dfecdcec4cf1bbc8810363",
47
+ subprocessors: "d45a3dc82df6aa5ba270a3066f544225848bcc8061934cfc910355f84c50f9a4",
48
48
  dataPortability: "27a7d3ec0175af8f3f1c67db1a65bf01f74d5139b44d9134caef5dd8a924d775",
49
49
  };
50
50
  /** Version of the canonical English Terms presented during account acceptance. */
51
51
  export const CURRENT_TERMS_VERSION = LEGAL_DOCUMENT_VERSIONS.terms;
52
52
  /** The "Last updated" date shared by the current revision of the documents. */
53
- export const LEGAL_DOCUMENT_LAST_UPDATED = "10 September 2026";
53
+ export const LEGAL_DOCUMENT_LAST_UPDATED = "24 September 2026";
54
54
  //# sourceMappingURL=legal.js.map
package/dist/legal.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"legal.js","sourceRoot":"","sources":["../src/legal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,KAAK,EAAE,KAAK;IACZ,GAAG,EAAE,KAAK;IACV,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,GAAG,EAAE,KAAK;IACV,aAAa,EAAE,KAAK;IACpB,eAAe,EAAE,KAAK;CACd,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,KAAK,EAAE,kEAAkE;IACzE,GAAG,EAAE,kEAAkE;IACvE,OAAO,EAAE,kEAAkE;IAC3E,OAAO,EAAE,kEAAkE;IAC3E,GAAG,EAAE,kEAAkE;IACvE,aAAa,EAAE,kEAAkE;IACjF,eAAe,EAAE,kEAAkE;CAC3E,CAAC;AAEX,kFAAkF;AAClF,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC,KAAK,CAAC;AAEnE,+EAA+E;AAC/E,MAAM,CAAC,MAAM,2BAA2B,GAAG,mBAAmB,CAAC"}
1
+ {"version":3,"file":"legal.js","sourceRoot":"","sources":["../src/legal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,OAAO;IACZ,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,OAAO;IAChB,GAAG,EAAE,KAAK;IACV,aAAa,EAAE,OAAO;IACtB,eAAe,EAAE,KAAK;CACd,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,KAAK,EAAE,kEAAkE;IACzE,GAAG,EAAE,kEAAkE;IACvE,OAAO,EAAE,kEAAkE;IAC3E,OAAO,EAAE,kEAAkE;IAC3E,GAAG,EAAE,kEAAkE;IACvE,aAAa,EAAE,kEAAkE;IACjF,eAAe,EAAE,kEAAkE;CAC3E,CAAC;AAEX,kFAAkF;AAClF,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC,KAAK,CAAC;AAEnE,+EAA+E;AAC/E,MAAM,CAAC,MAAM,2BAA2B,GAAG,mBAAmB,CAAC"}
@@ -26,6 +26,6 @@ export declare const DEFAULT_MCP_HTTP_PORT = 8787;
26
26
  * drifted to three different values (51/52/53), and one shipped artifact
27
27
  * disagreed with itself on two lines.
28
28
  */
29
- export declare const MCP_TOOL_COUNT_LOCAL = 53;
30
- export declare const MCP_TOOL_COUNT_HOSTED = 22;
29
+ export declare const MCP_TOOL_COUNT_LOCAL = 54;
30
+ export declare const MCP_TOOL_COUNT_HOSTED = 23;
31
31
  //# sourceMappingURL=platform.d.ts.map
package/dist/platform.js CHANGED
@@ -26,6 +26,6 @@ export const DEFAULT_MCP_HTTP_PORT = 8787;
26
26
  * drifted to three different values (51/52/53), and one shipped artifact
27
27
  * disagreed with itself on two lines.
28
28
  */
29
- export const MCP_TOOL_COUNT_LOCAL = 53;
30
- export const MCP_TOOL_COUNT_HOSTED = 22;
29
+ export const MCP_TOOL_COUNT_LOCAL = 54;
30
+ export const MCP_TOOL_COUNT_HOSTED = 23;
31
31
  //# sourceMappingURL=platform.js.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Constant-time equality for secrets, tokens and signatures that arrive as
3
+ * text. A subpath export (`@percher/shared/secure-compare`), never the
4
+ * barrel: the barrel is bundled into dashboard client components, and
5
+ * `node:crypto` there fails the web build. `timingSafeEqual` throws on buffers of different length, so callers
6
+ * guarded the length first, and most compared STRING length. A UTF-8 header
7
+ * with the same number of characters but more bytes ("é" vs "a") passed that
8
+ * guard and made the compare throw: a 500 where a 401 belonged. This compares
9
+ * byte length, and on a mismatch still runs one compare so the mismatch path
10
+ * does comparable work; it does not fully hide the length class (allocation
11
+ * and the branch remain), which is the same residual every caller had.
12
+ * Empty input never matches, including an empty expected value: two empty
13
+ * strings are not a shared secret.
14
+ */
15
+ export declare function secretEquals(provided: string | null | undefined, expected: string): boolean;
16
+ //# sourceMappingURL=secure-compare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-compare.d.ts","sourceRoot":"","sources":["../src/secure-compare.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAS3F"}
@@ -0,0 +1,27 @@
1
+ import { timingSafeEqual } from "node:crypto";
2
+ /**
3
+ * Constant-time equality for secrets, tokens and signatures that arrive as
4
+ * text. A subpath export (`@percher/shared/secure-compare`), never the
5
+ * barrel: the barrel is bundled into dashboard client components, and
6
+ * `node:crypto` there fails the web build. `timingSafeEqual` throws on buffers of different length, so callers
7
+ * guarded the length first, and most compared STRING length. A UTF-8 header
8
+ * with the same number of characters but more bytes ("é" vs "a") passed that
9
+ * guard and made the compare throw: a 500 where a 401 belonged. This compares
10
+ * byte length, and on a mismatch still runs one compare so the mismatch path
11
+ * does comparable work; it does not fully hide the length class (allocation
12
+ * and the branch remain), which is the same residual every caller had.
13
+ * Empty input never matches, including an empty expected value: two empty
14
+ * strings are not a shared secret.
15
+ */
16
+ export function secretEquals(provided, expected) {
17
+ if (!provided || !expected)
18
+ return false;
19
+ const a = Buffer.from(provided, "utf8");
20
+ const b = Buffer.from(expected, "utf8");
21
+ if (a.length !== b.length) {
22
+ timingSafeEqual(b, b);
23
+ return false;
24
+ }
25
+ return timingSafeEqual(a, b);
26
+ }
27
+ //# sourceMappingURL=secure-compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-compare.js","sourceRoot":"","sources":["../src/secure-compare.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAAC,QAAmC,EAAE,QAAgB;IAChF,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IACzC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;QAC1B,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/B,CAAC"}
@@ -11,7 +11,7 @@
11
11
  /** Request header the signup form uses to carry the code through BetterAuth. */
12
12
  export declare const SIGNUP_INVITE_HEADER = "x-percher-invite-code";
13
13
  export declare const SIGNUP_INVITE_CODE_PREFIX = "beta-";
14
- /** Random part is lowercase base36, so a code survives being typed or spoken. */
14
+ /** Legacy code shape. Previously issued codes retain their exact hash. */
15
15
  export declare const SIGNUP_INVITE_CODE_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
16
16
  export declare const SIGNUP_INVITE_CODE_LENGTH = 24;
17
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"signup-invite.d.ts","sourceRoot":"","sources":["../src/signup-invite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAE5D,eAAO,MAAM,yBAAyB,UAAU,CAAC;AAEjD,iFAAiF;AACjF,eAAO,MAAM,2BAA2B,yCAAyC,CAAC;AAClF,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAI5C;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAIvF"}
1
+ {"version":3,"file":"signup-invite.d.ts","sourceRoot":"","sources":["../src/signup-invite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAE5D,eAAO,MAAM,yBAAyB,UAAU,CAAC;AAEjD,0EAA0E;AAC1E,eAAO,MAAM,2BAA2B,yCAAyC,CAAC;AAClF,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAK5C;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAOvF"}
@@ -11,10 +11,11 @@
11
11
  /** Request header the signup form uses to carry the code through BetterAuth. */
12
12
  export const SIGNUP_INVITE_HEADER = "x-percher-invite-code";
13
13
  export const SIGNUP_INVITE_CODE_PREFIX = "beta-";
14
- /** Random part is lowercase base36, so a code survives being typed or spoken. */
14
+ /** Legacy code shape. Previously issued codes retain their exact hash. */
15
15
  export const SIGNUP_INVITE_CODE_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
16
16
  export const SIGNUP_INVITE_CODE_LENGTH = 24;
17
17
  const CODE_RE = /^beta-[a-z0-9]{24}$/;
18
+ const WORD_CODE_RE = /^beta[- ][a-z]{3,8}(?:[- ][a-z]{3,8}){3}$/;
18
19
  /**
19
20
  * Canonical form of a code as a user might have typed it: whitespace trimmed,
20
21
  * case folded. Returns null for anything that is not shaped like a code, so
@@ -24,6 +25,10 @@ export function normalizeSignupInviteCode(raw) {
24
25
  if (typeof raw !== "string")
25
26
  return null;
26
27
  const code = raw.trim().toLowerCase();
27
- return CODE_RE.test(code) ? code : null;
28
+ if (CODE_RE.test(code))
29
+ return code;
30
+ // Four complete words, with single spaces or hyphens as spoken separators.
31
+ // The private API owns the vocabulary; only a stored hash authorizes signup.
32
+ return WORD_CODE_RE.test(code) ? code.replaceAll(" ", "-") : null;
28
33
  }
29
34
  //# sourceMappingURL=signup-invite.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"signup-invite.js","sourceRoot":"","sources":["../src/signup-invite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gFAAgF;AAChF,MAAM,CAAC,MAAM,oBAAoB,GAAG,uBAAuB,CAAC;AAE5D,MAAM,CAAC,MAAM,yBAAyB,GAAG,OAAO,CAAC;AAEjD,iFAAiF;AACjF,MAAM,CAAC,MAAM,2BAA2B,GAAG,sCAAsC,CAAC;AAClF,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAE5C,MAAM,OAAO,GAAG,qBAAqB,CAAC;AAEtC;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,GAA8B;IACtE,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACtC,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1C,CAAC"}
1
+ {"version":3,"file":"signup-invite.js","sourceRoot":"","sources":["../src/signup-invite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gFAAgF;AAChF,MAAM,CAAC,MAAM,oBAAoB,GAAG,uBAAuB,CAAC;AAE5D,MAAM,CAAC,MAAM,yBAAyB,GAAG,OAAO,CAAC;AAEjD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,2BAA2B,GAAG,sCAAsC,CAAC;AAClF,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAE5C,MAAM,OAAO,GAAG,qBAAqB,CAAC;AACtC,MAAM,YAAY,GAAG,2CAA2C,CAAC;AAEjE;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,GAA8B;IACtE,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACtC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,2EAA2E;IAC3E,6EAA6E;IAC7E,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACpE,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Every environment switch the platform reads, declared once.
3
+ *
4
+ * A switch is a variable that selects a code path (two paths, an enum of
5
+ * modes, or "armed when present"), as opposed to configuration such as a URL
6
+ * or a size. The readers spell their comparisons differently (`=== "1"` in
7
+ * most places, `=== "true"` in five, `!== "0"` for a default-on switch), and
8
+ * an operator who set `=1` on a `"true"` switch got the OFF path with no
9
+ * warning. This registry records each switch's EXISTING accepted spellings.
10
+ * `switchState` names the four states a raw value can be in, and
11
+ * `assertValidSwitches` refuses a boot on an invalid one. Readers resolve a
12
+ * switch through `switchEnabled` / `switchValue`, which return exactly what
13
+ * the literal comparisons they replaced returned;
14
+ * `test/switch-readers-parity.test.ts` holds those comparisons and the
15
+ * switches still read the old way.
16
+ *
17
+ * Widening a reader to accept both spellings is deliberately not done here:
18
+ * a value that is off today because of its spelling would turn on silently
19
+ * at the next deploy. Fix the value, deliberately, one switch at a time.
20
+ */
21
+ export type SwitchReader = "api" | "worker" | "dashboard" | "mcp" | "cli";
22
+ export type SwitchState = "enabled" | "disabled" | "unset" | "invalid";
23
+ interface SwitchBase {
24
+ name: string;
25
+ readers: readonly SwitchReader[];
26
+ /** One line: what the ON path does. */
27
+ purpose: string;
28
+ }
29
+ export interface BooleanSwitch extends SwitchBase {
30
+ kind: "boolean";
31
+ /** Raw spellings the readers treat as ON today. */
32
+ enabled: readonly string[];
33
+ /** Raw spellings that mean an explicit OFF (never reported as invalid). */
34
+ disabled: readonly string[];
35
+ /** What an unset variable resolves to. */
36
+ default: "enabled" | "disabled";
37
+ }
38
+ export interface EnumSwitch extends SwitchBase {
39
+ kind: "enum";
40
+ values: readonly string[];
41
+ /** The value an unset variable resolves to. */
42
+ default: string;
43
+ /** The reader trims and lowercases before comparing, so `" ENFORCE "` works. */
44
+ normalize?: true;
45
+ }
46
+ export interface PresenceSwitch extends SwitchBase {
47
+ kind: "presence";
48
+ }
49
+ export type SwitchSpec = BooleanSwitch | EnumSwitch | PresenceSwitch;
50
+ /** The registry. Order: builders, isolation, admission, product, ops, levers. */
51
+ export declare const SWITCHES: readonly SwitchSpec[];
52
+ export declare const SWITCH_BY_NAME: ReadonlyMap<string, SwitchSpec>;
53
+ /** The state a raw value puts a switch in, by that switch's own spellings. */
54
+ export declare function switchState(spec: SwitchSpec, raw: string | undefined): SwitchState;
55
+ type Env = Record<string, string | undefined>;
56
+ /**
57
+ * The path a boolean switch selects: ON for an enabled spelling, OFF for a
58
+ * disabled one, and the switch's default when unset or invalid. That is what
59
+ * every `=== "1"` / `!== "0"` reader returned, so moving a reader here changes
60
+ * no verdict.
61
+ */
62
+ export declare function switchEnabled(name: string, env: Env): boolean;
63
+ /** The mode an enum switch selects: its (normalized) value, or the default when unset or invalid. */
64
+ export declare function switchValue(name: string, env: Env): string;
65
+ export interface SwitchReport {
66
+ name: string;
67
+ raw: string;
68
+ state: SwitchState;
69
+ /** What the value should have been spelled as. */
70
+ accepted: readonly string[];
71
+ /** What an unset variable resolves to. */
72
+ fallback: string;
73
+ }
74
+ /**
75
+ * The switches whose raw value is set but not a spelling any reader accepts.
76
+ * The input to the boot refusal; it never throws.
77
+ */
78
+ export declare function reportSwitches(env: Record<string, string | undefined>, reader?: SwitchReader): SwitchReport[];
79
+ /**
80
+ * Refuse to boot on a set-but-invalid switch: the reader would silently take
81
+ * its default path, which is how a `"true"` switch set to `1` stayed off.
82
+ * A disabled spelling and an unset variable never refuse. The error names
83
+ * every invalid switch with its raw value and accepted spellings. Call it
84
+ * before any other boot guard and before any listener starts.
85
+ */
86
+ export declare function assertValidSwitches(env: Record<string, string | undefined>, reader: SwitchReader): void;
87
+ export {};
88
+ //# sourceMappingURL=switches.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switches.d.ts","sourceRoot":"","sources":["../src/switches.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,GAAG,WAAW,GAAG,KAAK,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAEvE,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,IAAI,EAAE,SAAS,CAAC;IAChB,mDAAmD;IACnD,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,0CAA0C;IAC1C,OAAO,EAAE,SAAS,GAAG,UAAU,CAAC;CACjC;AAED,MAAM,WAAW,UAAW,SAAQ,UAAU;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,UAAU,GAAG,cAAc,CAAC;AA2BrE,iFAAiF;AACjF,eAAO,MAAM,QAAQ,EAAE,SAAS,UAAU,EAkPzC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAE1D,CAAC;AAEF,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAclF;AAED,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAW9C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAM7D;AAED,qGAAqG;AACrG,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,CAK1D;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,WAAW,CAAC;IACnB,kDAAkD;IAClD,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,MAAM,CAAC,EAAE,YAAY,GACpB,YAAY,EAAE,CAiBhB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,MAAM,EAAE,YAAY,GACnB,IAAI,CAaN"}
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Every environment switch the platform reads, declared once.
3
+ *
4
+ * A switch is a variable that selects a code path (two paths, an enum of
5
+ * modes, or "armed when present"), as opposed to configuration such as a URL
6
+ * or a size. The readers spell their comparisons differently (`=== "1"` in
7
+ * most places, `=== "true"` in five, `!== "0"` for a default-on switch), and
8
+ * an operator who set `=1` on a `"true"` switch got the OFF path with no
9
+ * warning. This registry records each switch's EXISTING accepted spellings.
10
+ * `switchState` names the four states a raw value can be in, and
11
+ * `assertValidSwitches` refuses a boot on an invalid one. Readers resolve a
12
+ * switch through `switchEnabled` / `switchValue`, which return exactly what
13
+ * the literal comparisons they replaced returned;
14
+ * `test/switch-readers-parity.test.ts` holds those comparisons and the
15
+ * switches still read the old way.
16
+ *
17
+ * Widening a reader to accept both spellings is deliberately not done here:
18
+ * a value that is off today because of its spelling would turn on silently
19
+ * at the next deploy. Fix the value, deliberately, one switch at a time.
20
+ */
21
+ const ONE = ["1"];
22
+ const TRUE = ["true"];
23
+ const OFF_SPELLINGS = ["0", "false"];
24
+ // A default-on reader is written `!== "0"` (or `!== "false"`), which puts
25
+ // EVERY other spelling on the ON side; its disabled list is exactly that one
26
+ // literal, never both conventional spellings, or the registry would report as
27
+ // OFF a value the reader turns ON.
28
+ const bool = (name, readers, purpose, enabled, def = "disabled", disabled = OFF_SPELLINGS) => ({
29
+ kind: "boolean",
30
+ name,
31
+ readers,
32
+ purpose,
33
+ enabled,
34
+ disabled,
35
+ default: def,
36
+ });
37
+ /** The registry. Order: builders, isolation, admission, product, ops, levers. */
38
+ export const SWITCHES = [
39
+ // Build dispatch
40
+ bool("PERCHER_NODE_USE_DOCKERFILE", ["api"], 'Node/Bun apps build through the Percher Dockerfile instead of Nixpacks (default; "0" is the emergency lever)', ONE, "enabled", ["0"]),
41
+ bool("PERCHER_PYTHON_USE_DOCKERFILE", ["api"], 'Python apps build through the Percher Dockerfile instead of Nixpacks (default; "0" is the emergency lever)', ONE, "enabled", ["0"]),
42
+ bool("PERCHER_OPS_BUILD_TRIAGE", ["api"], "append the internal cold-build triage block to build logs", ONE),
43
+ bool("PERCHER_CAPPED_BUILDER_ACTIVE", ["worker"], "builds run on the capped buildx builder; set by the worker itself once that builder is ready, not by the operator", ONE),
44
+ // Tenant isolation and networks
45
+ bool("PERCHER_PER_APP_NETWORKS", ["api", "worker"], "per-app internal networks, pbproxy and per-app egress (production refuses to boot without it)", TRUE),
46
+ bool("PERCHER_CADDY_RATELIMIT_ENABLED", ["api"], "emit Caddy rate_limit handlers for apps that declare [web].rate_limit", ONE),
47
+ bool("PERCHER_UNKNOWN_HOST_404", ["api"], "answer app-suffix hosts that no route serves with a 404 instead of Caddy's empty 200", ONE),
48
+ bool("PERCHER_PB_AUTH_RATELIMIT_ENABLED", ["api"], "limit login, OTP and account-mail requests per client IP on public PocketBase hosts", ONE),
49
+ bool("PERCHER_EGRESS_PROBE", ["api"], "run the in-container egress probe in diagnostics", ONE),
50
+ bool("PERCHER_WILDCARD_TLS", ["api"], "one wildcard DNS-01 certificate instead of per-host certificates", ONE),
51
+ // Admission and disk
52
+ bool("PERCHER_MEASURED_ADMISSION", ["api"], "measured admission, overcommit and box eviction instead of reservation accounting", ONE),
53
+ {
54
+ kind: "enum",
55
+ name: "PERCHER_DISK_GATE",
56
+ readers: ["api"],
57
+ purpose: "refuse uploads when disk state is unknown (required) or allow them (off)",
58
+ values: ["required", "off"],
59
+ default: "required",
60
+ },
61
+ bool("DISK_PRESSURE_AUTO_SUSPEND", ["api"], "auto-suspend PocketBase apps after the disk-pressure grace timeline", TRUE),
62
+ bool("PERCHER_APPDATA_HARD_CAP_ENFORCE", ["api"], "suspend an app immediately when its appdata exceeds the hard cap", TRUE),
63
+ // Accounts and product surface
64
+ bool("PERCHER_REQUIRE_EMAIL_VERIFICATION", ["api"], "block API use until the account's email is verified", ONE),
65
+ bool("PERCHER_ANON_DEPLOYS", ["api"], "open the anonymous deploy lane", ONE),
66
+ bool("PERCHER_SUPPORT_ENABLED", ["api"], "mount the support routes and jobs", ONE),
67
+ bool("PERCHER_SUPPORT_DIGEST_SEND_EMPTY", ["api"], "send the daily support digest even when it is empty", ONE),
68
+ bool("PERCHER_HOSTED_MCP_ENABLED", ["api"], "mount the OAuth authorization server and register mcp.percher.app", ONE),
69
+ bool("PERCHER_LEGAL_NOTICES_ENABLED", ["api"], "send material legal-change notices instead of reporting only", ONE),
70
+ bool("PERCHER_DEPLOY_SCREENSHOTS", ["api", "worker"], "capture a post-deploy screenshot with headless Chromium", ONE),
71
+ bool("PERCHER_RUNTIME_ERROR_CAPTURE", ["api"], "capture runtime errors over CDP instead of the log-trick screenshot", ONE),
72
+ {
73
+ kind: "enum",
74
+ name: "PERCHER_MANAGED_INFERENCE_MODE",
75
+ readers: ["api"],
76
+ purpose: "managed inference enabled (subject to credentials and approval) or disabled",
77
+ values: ["disabled", "enabled"],
78
+ default: "disabled",
79
+ },
80
+ // Deploy pipeline
81
+ bool("PERCHER_CANARY_AUTO_ROLLBACK", ["api"], "roll back on a canary failure instead of logging", TRUE, "enabled", ["false"]),
82
+ bool("PERCHER_CANARY_EDGE_KEEPS_LIVE", ["api"], "keep a deploy live when the canary failure was Percher's own edge", ONE, "enabled", ["0"]),
83
+ bool("PERCHER_DRAIN_AT_SETTLEMENT", ["api"], "drain the predecessor at canary settlement instead of on a timer", ONE, "enabled", ["0"]),
84
+ // Security scanning
85
+ bool("SECURITY_BLOCK_DEPLOY", ["api"], "block the swap on red scan findings instead of advising", TRUE),
86
+ bool("SECURITY_AUTO_HOLD", ["api"], "runtime re-scan places red apps on security hold automatically", TRUE),
87
+ {
88
+ kind: "enum",
89
+ name: "PERCHER_INTERNAL_SIG_MODE",
90
+ readers: ["api"],
91
+ purpose: "HMAC signing of /internal/* calls: off, log or enforce",
92
+ values: ["off", "log", "enforce"],
93
+ default: "off",
94
+ },
95
+ bool("METRICS_PUBLIC", ["api"], "serve /metrics without the internal secret", TRUE),
96
+ // Dashboard
97
+ {
98
+ kind: "enum",
99
+ name: "PERCHER_CONTROL_CSP",
100
+ readers: ["dashboard"],
101
+ purpose: "content-security policy off, report-only or enforced",
102
+ values: ["off", "report", "enforce"],
103
+ default: "report",
104
+ normalize: true,
105
+ },
106
+ bool("NEXT_PUBLIC_PERCHER_E2E", ["dashboard"], "compile the e2e login-as route into the bundle (build time)", ONE),
107
+ {
108
+ kind: "presence",
109
+ name: "PERCHER_E2E_SECRET",
110
+ readers: ["dashboard"],
111
+ purpose: "the e2e login-as route works when set",
112
+ },
113
+ bool("PERCHER_ALLOW_NO_CAPTCHA", ["dashboard"], "allow production without Turnstile", ONE),
114
+ bool("PERCHER_ALLOW_UNVERIFIED_SIGNUP", ["dashboard"], "allow production without Resend", ONE),
115
+ // Boot-guard opt-outs and topology
116
+ bool("PERCHER_ALLOW_NO_ALERTING", ["api"], "boot without an alert channel", ONE),
117
+ {
118
+ kind: "presence",
119
+ name: "PERCHER_WORKER_URL",
120
+ readers: ["api"],
121
+ purpose: "proxy container operations to the worker daemon (production topology) when set",
122
+ },
123
+ {
124
+ kind: "presence",
125
+ name: "PLATFORM_SUNSET_DATE",
126
+ readers: ["api"],
127
+ purpose: "sunset mode: banners, emails and the deletion schedule, when set",
128
+ },
129
+ // Client telemetry opt-outs
130
+ bool("PERCHER_NO_TELEMETRY", ["cli", "mcp"], "client telemetry off", ["1", "true"]),
131
+ bool("DO_NOT_TRACK", ["cli", "mcp"], "client telemetry off (the cross-tool convention)", ONE),
132
+ // Withdrawn provider seam
133
+ {
134
+ kind: "enum",
135
+ name: "CRASH_ANALYZER_PROVIDER",
136
+ readers: ["api"],
137
+ purpose: "the fake crash analyzer for tests, or none",
138
+ values: ["fake", "disabled"],
139
+ default: "disabled",
140
+ },
141
+ ];
142
+ export const SWITCH_BY_NAME = new Map(SWITCHES.map((s) => [s.name, s]));
143
+ /** The state a raw value puts a switch in, by that switch's own spellings. */
144
+ export function switchState(spec, raw) {
145
+ if (raw === undefined || raw === "")
146
+ return "unset";
147
+ switch (spec.kind) {
148
+ case "boolean":
149
+ if (spec.enabled.includes(raw))
150
+ return "enabled";
151
+ if (spec.disabled.includes(raw))
152
+ return "disabled";
153
+ return "invalid";
154
+ case "enum": {
155
+ const value = spec.normalize ? raw.trim().toLowerCase() : raw;
156
+ return spec.values.includes(value) ? "enabled" : "invalid";
157
+ }
158
+ case "presence":
159
+ return "enabled";
160
+ }
161
+ }
162
+ function registered(name, kind) {
163
+ const spec = SWITCH_BY_NAME.get(name);
164
+ if (spec?.kind !== kind)
165
+ throw new Error(`${name} is not a registered ${kind} switch`);
166
+ return spec;
167
+ }
168
+ /**
169
+ * The path a boolean switch selects: ON for an enabled spelling, OFF for a
170
+ * disabled one, and the switch's default when unset or invalid. That is what
171
+ * every `=== "1"` / `!== "0"` reader returned, so moving a reader here changes
172
+ * no verdict.
173
+ */
174
+ export function switchEnabled(name, env) {
175
+ const spec = registered(name, "boolean");
176
+ const state = switchState(spec, env[name]);
177
+ if (state === "enabled")
178
+ return true;
179
+ if (state === "disabled")
180
+ return false;
181
+ return spec.default === "enabled";
182
+ }
183
+ /** The mode an enum switch selects: its (normalized) value, or the default when unset or invalid. */
184
+ export function switchValue(name, env) {
185
+ const spec = registered(name, "enum");
186
+ const raw = env[name];
187
+ if (raw === undefined || switchState(spec, raw) !== "enabled")
188
+ return spec.default;
189
+ return spec.normalize ? raw.trim().toLowerCase() : raw;
190
+ }
191
+ /**
192
+ * The switches whose raw value is set but not a spelling any reader accepts.
193
+ * The input to the boot refusal; it never throws.
194
+ */
195
+ export function reportSwitches(env, reader) {
196
+ const out = [];
197
+ for (const spec of SWITCHES) {
198
+ if (reader && !spec.readers.includes(reader))
199
+ continue;
200
+ const raw = env[spec.name];
201
+ const state = switchState(spec, raw);
202
+ if (state !== "invalid" || raw === undefined)
203
+ continue;
204
+ const accepted = spec.kind === "boolean"
205
+ ? [...spec.enabled, ...spec.disabled]
206
+ : spec.kind === "enum"
207
+ ? spec.values
208
+ : [];
209
+ const fallback = spec.kind === "presence" ? "unset" : spec.default;
210
+ out.push({ name: spec.name, raw, state, accepted, fallback });
211
+ }
212
+ return out;
213
+ }
214
+ /**
215
+ * Refuse to boot on a set-but-invalid switch: the reader would silently take
216
+ * its default path, which is how a `"true"` switch set to `1` stayed off.
217
+ * A disabled spelling and an unset variable never refuse. The error names
218
+ * every invalid switch with its raw value and accepted spellings. Call it
219
+ * before any other boot guard and before any listener starts.
220
+ */
221
+ export function assertValidSwitches(env, reader) {
222
+ const invalid = reportSwitches(env, reader);
223
+ if (invalid.length === 0)
224
+ return;
225
+ throw new Error(invalid
226
+ .map((r) => `[percher-${reader}] refusing to start: ${r.name}=${JSON.stringify(r.raw)} is not a spelling this switch accepts. ` +
227
+ `Accepted: ${r.accepted.map((a) => JSON.stringify(a)).join(", ")}. ` +
228
+ `Unset it for the default (${r.fallback}).`)
229
+ .join("\n"));
230
+ }
231
+ //# sourceMappingURL=switches.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switches.js","sourceRoot":"","sources":["../src/switches.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percher/shared",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Shared constants and contracts (timeouts, etc.) used across the Percher CLI, API, MCP, and worker. Internal — values change in lockstep across packages.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -36,6 +36,11 @@
36
36
  "import": "./dist/pow.js",
37
37
  "default": "./dist/pow.js"
38
38
  },
39
+ "./secure-compare": {
40
+ "types": "./dist/secure-compare.d.ts",
41
+ "import": "./dist/secure-compare.js",
42
+ "default": "./dist/secure-compare.js"
43
+ },
39
44
  "./signup-invite-hash": {
40
45
  "types": "./dist/signup-invite-hash.d.ts",
41
46
  "import": "./dist/signup-invite-hash.js",