@ttt-productions/ttt-core 0.79.49 → 0.79.51
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/dist/constants/craft-skill-statements.d.ts +20 -0
- package/dist/constants/craft-skill-statements.d.ts.map +1 -1
- package/dist/constants/craft-skill-statements.js +25 -9
- package/dist/constants/craft-skill-statements.js.map +1 -1
- package/dist/constants/legal-review-notice.d.ts +3 -0
- package/dist/constants/legal-review-notice.d.ts.map +1 -1
- package/dist/constants/legal-review-notice.js +3 -0
- package/dist/constants/legal-review-notice.js.map +1 -1
- package/dist/constants/public-documents.d.ts +7 -0
- package/dist/constants/public-documents.d.ts.map +1 -1
- package/dist/constants/public-documents.js +7 -0
- package/dist/constants/public-documents.js.map +1 -1
- package/dist/doc-schemas/ncii/config.d.ts +1 -5
- package/dist/doc-schemas/ncii/config.d.ts.map +1 -1
- package/dist/doc-schemas/ncii/config.js +8 -19
- package/dist/doc-schemas/ncii/config.js.map +1 -1
- package/dist/doc-schemas/operational.d.ts +47 -2
- package/dist/doc-schemas/operational.d.ts.map +1 -1
- package/dist/doc-schemas/operational.js +32 -7
- package/dist/doc-schemas/operational.js.map +1 -1
- package/dist/doc-schemas/registry.d.ts +14 -7
- package/dist/doc-schemas/registry.d.ts.map +1 -1
- package/dist/doc-schemas/system.d.ts.map +1 -1
- package/dist/doc-schemas/system.js +2 -0
- package/dist/doc-schemas/system.js.map +1 -1
- package/dist/schemas/public-documents.d.ts +25 -0
- package/dist/schemas/public-documents.d.ts.map +1 -1
- package/dist/schemas/public-documents.js +20 -8
- package/dist/schemas/public-documents.js.map +1 -1
- package/dist/schemas/users.d.ts +17 -0
- package/dist/schemas/users.d.ts.map +1 -1
- package/dist/schemas/users.js +13 -0
- package/dist/schemas/users.js.map +1 -1
- package/dist/schemas/utility.d.ts +2 -0
- package/dist/schemas/utility.d.ts.map +1 -1
- package/dist/schemas/utility.js +5 -2
- package/dist/schemas/utility.js.map +1 -1
- package/dist/utils/app-config.d.ts +26 -0
- package/dist/utils/app-config.d.ts.map +1 -0
- package/dist/utils/app-config.js +58 -0
- package/dist/utils/app-config.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/public-documents.d.ts +14 -0
- package/dist/utils/public-documents.d.ts.map +1 -1
- package/dist/utils/public-documents.js +20 -0
- package/dist/utils/public-documents.js.map +1 -1
- package/package.json +1 -1
|
@@ -7,4 +7,24 @@ export declare const CRAFT_SKILL_KIND_LABELS: Record<CraftSkillKind, string>;
|
|
|
7
7
|
export declare const CRAFT_SKILL_KIND_DESCRIPTIONS: Record<CraftSkillKind, string>;
|
|
8
8
|
export declare const CRAFT_SKILL_STATEMENTS: Record<CraftSkillKind, string>;
|
|
9
9
|
export declare const CRAFT_SKILL_KIND_ORDER: CraftSkillKind[];
|
|
10
|
+
/**
|
|
11
|
+
* Why "Mimicked work from outside TTT Productions" cannot be chosen yet: the picker shows it
|
|
12
|
+
* when a person selects that kind, and the upload callable refuses the kind with the same words.
|
|
13
|
+
*/
|
|
14
|
+
export declare const CRAFT_SKILL_MIMIC_OFF_TTT_UNAVAILABLE_MESSAGE = "This option isn't available yet: sharing covers or recreations of work from outside TTT needs legal review first.";
|
|
15
|
+
/**
|
|
16
|
+
* The ONE owner of which craft kinds are blocked at launch, with each one's refusal copy. A
|
|
17
|
+
* blocked kind still renders in the picker (so people see it is coming) but selecting it stops
|
|
18
|
+
* the flow with this copy, and the upload callable refuses it with the same words. Unblocking a
|
|
19
|
+
* kind is removing its entry here.
|
|
20
|
+
*/
|
|
21
|
+
export declare const CRAFT_SKILL_KIND_UNAVAILABLE_MESSAGES: {
|
|
22
|
+
readonly mimicOffTtt: "This option isn't available yet: sharing covers or recreations of work from outside TTT needs legal review first.";
|
|
23
|
+
};
|
|
24
|
+
/** A craft kind that is blocked at launch. */
|
|
25
|
+
export type BlockedCraftSkillKind = keyof typeof CRAFT_SKILL_KIND_UNAVAILABLE_MESSAGES;
|
|
26
|
+
/** Every craft kind blocked at launch — derived from the refusal copy, never restated. */
|
|
27
|
+
export declare const BLOCKED_CRAFT_SKILL_KINDS: readonly BlockedCraftSkillKind[];
|
|
28
|
+
/** True when `kind` is blocked at launch; narrows it to index its refusal copy. */
|
|
29
|
+
export declare function isBlockedCraftSkillKind(kind: CraftSkillKind): kind is BlockedCraftSkillKind;
|
|
10
30
|
//# sourceMappingURL=craft-skill-statements.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"craft-skill-statements.d.ts","sourceRoot":"","sources":["../../src/constants/craft-skill-statements.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"craft-skill-statements.d.ts","sourceRoot":"","sources":["../../src/constants/craft-skill-statements.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D;kEACkE;AAClE,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAIlE,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAIxE,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAOjE,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,cAAc,EAA8C,CAAC;AAElG;;;GAGG;AACH,eAAO,MAAM,6CAA6C,sHAC2D,CAAC;AAEtH;;;;;GAKG;AACH,eAAO,MAAM,qCAAqC;;CAEU,CAAC;AAE7D,8CAA8C;AAC9C,MAAM,MAAM,qBAAqB,GAAG,MAAM,OAAO,qCAAqC,CAAC;AAEvF,0FAA0F;AAC1F,eAAO,MAAM,yBAAyB,EAEjC,SAAS,qBAAqB,EAAE,CAAC;AAEtC,mFAAmF;AACnF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,IAAI,qBAAqB,CAE3F"}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
// ============================================================================
|
|
2
2
|
// CRAFT-SKILL ATTESTATION — the ONE home for the three-kind upload flow's
|
|
3
|
-
// statement version, VERBATIM agreement statements
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// `
|
|
8
|
-
// mirror). The client displays these and the user must explicitly agree before
|
|
9
|
-
// the file picker unlocks; the backend records only `{ statementKind,
|
|
10
|
-
// statementVersion, agreedAt }` and validates the version against
|
|
11
|
-
// CRAFT_SKILL_STATEMENT_VERSION.
|
|
3
|
+
// statement version, VERBATIM agreement statements, kind labels/descriptions,
|
|
4
|
+
// picker order, and the refusal copy for a kind that is not available yet. The
|
|
5
|
+
// client displays these and the user must explicitly agree before the file
|
|
6
|
+
// picker unlocks; the backend records only `{ statementKind, statementVersion,
|
|
7
|
+
// agreedAt }` and validates the version against CRAFT_SKILL_STATEMENT_VERSION.
|
|
12
8
|
// ============================================================================
|
|
13
9
|
/** Bump when any VERBATIM statement below changes; the version is recorded on every
|
|
14
10
|
* craft-skill doc so we know which wording the user agreed to. */
|
|
@@ -30,4 +26,24 @@ export const CRAFT_SKILL_STATEMENTS = {
|
|
|
30
26
|
mimicOffTtt: 'This craft skill is my performance or recreation of a work that did not originate on TTT Productions (including public-domain or out-of-copyright works), shown only to demonstrate my abilities. The underlying work belongs to its owner, and I claim no ownership of it. I understand TTT Productions may remove this content at any time, including in response to a rights-holder request.',
|
|
31
27
|
};
|
|
32
28
|
export const CRAFT_SKILL_KIND_ORDER = ['original', 'mimicOnTtt', 'mimicOffTtt'];
|
|
29
|
+
/**
|
|
30
|
+
* Why "Mimicked work from outside TTT Productions" cannot be chosen yet: the picker shows it
|
|
31
|
+
* when a person selects that kind, and the upload callable refuses the kind with the same words.
|
|
32
|
+
*/
|
|
33
|
+
export const CRAFT_SKILL_MIMIC_OFF_TTT_UNAVAILABLE_MESSAGE = "This option isn't available yet: sharing covers or recreations of work from outside TTT needs legal review first.";
|
|
34
|
+
/**
|
|
35
|
+
* The ONE owner of which craft kinds are blocked at launch, with each one's refusal copy. A
|
|
36
|
+
* blocked kind still renders in the picker (so people see it is coming) but selecting it stops
|
|
37
|
+
* the flow with this copy, and the upload callable refuses it with the same words. Unblocking a
|
|
38
|
+
* kind is removing its entry here.
|
|
39
|
+
*/
|
|
40
|
+
export const CRAFT_SKILL_KIND_UNAVAILABLE_MESSAGES = {
|
|
41
|
+
mimicOffTtt: CRAFT_SKILL_MIMIC_OFF_TTT_UNAVAILABLE_MESSAGE,
|
|
42
|
+
};
|
|
43
|
+
/** Every craft kind blocked at launch — derived from the refusal copy, never restated. */
|
|
44
|
+
export const BLOCKED_CRAFT_SKILL_KINDS = Object.keys(CRAFT_SKILL_KIND_UNAVAILABLE_MESSAGES);
|
|
45
|
+
/** True when `kind` is blocked at launch; narrows it to index its refusal copy. */
|
|
46
|
+
export function isBlockedCraftSkillKind(kind) {
|
|
47
|
+
return Object.prototype.hasOwnProperty.call(CRAFT_SKILL_KIND_UNAVAILABLE_MESSAGES, kind);
|
|
48
|
+
}
|
|
33
49
|
//# sourceMappingURL=craft-skill-statements.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"craft-skill-statements.js","sourceRoot":"","sources":["../../src/constants/craft-skill-statements.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,0EAA0E;AAC1E,+EAA+E;AAC/E,
|
|
1
|
+
{"version":3,"file":"craft-skill-statements.js","sourceRoot":"","sources":["../../src/constants/craft-skill-statements.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,0EAA0E;AAC1E,8EAA8E;AAC9E,+EAA+E;AAC/E,2EAA2E;AAC3E,+EAA+E;AAC/E,+EAA+E;AAC/E,+EAA+E;AAI/E;kEACkE;AAClE,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,uBAAuB,GAAmC;IACrE,QAAQ,EAAE,aAAa;IACvB,UAAU,EAAE,oCAAoC;IAChD,WAAW,EAAE,4CAA4C;CAC1D,CAAC;AAEF,kEAAkE;AAClE,MAAM,CAAC,MAAM,6BAA6B,GAAmC;IAC3E,QAAQ,EAAE,sCAAsC;IAChD,UAAU,EAAE,gFAAgF;IAC5F,WAAW,EAAE,iFAAiF;CAC/F,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAmC;IACpE,QAAQ,EACN,qJAAqJ;IACvJ,UAAU,EACR,oRAAoR;IACtR,WAAW,EACT,iYAAiY;CACpY,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAqB,CAAC,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;AAElG;;;GAGG;AACH,MAAM,CAAC,MAAM,6CAA6C,GACxD,mHAAmH,CAAC;AAEtH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qCAAqC,GAAG;IACnD,WAAW,EAAE,6CAA6C;CACA,CAAC;AAK7D,0FAA0F;AAC1F,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC,IAAI,CAClD,qCAAqC,CACF,CAAC;AAEtC,mFAAmF;AACnF,MAAM,UAAU,uBAAuB,CAAC,IAAoB;IAC1D,OAAO,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,qCAAqC,EAAE,IAAI,CAAC,CAAC;AAC3F,CAAC","sourcesContent":["// ============================================================================\n// CRAFT-SKILL ATTESTATION — the ONE home for the three-kind upload flow's\n// statement version, VERBATIM agreement statements, kind labels/descriptions,\n// picker order, and the refusal copy for a kind that is not available yet. The\n// client displays these and the user must explicitly agree before the file\n// picker unlocks; the backend records only `{ statementKind, statementVersion,\n// agreedAt }` and validates the version against CRAFT_SKILL_STATEMENT_VERSION.\n// ============================================================================\n\nimport type { CraftSkillKind } from '../doc-schemas/user.js';\n\n/** Bump when any VERBATIM statement below changes; the version is recorded on every\n * craft-skill doc so we know which wording the user agreed to. */\nexport const CRAFT_SKILL_STATEMENT_VERSION = 1;\n\nexport const CRAFT_SKILL_KIND_LABELS: Record<CraftSkillKind, string> = {\n original: 'My own work',\n mimicOnTtt: 'Mimicked work from TTT Productions',\n mimicOffTtt: 'Mimicked work from outside TTT Productions',\n};\n\n/** One-line helper shown under each kind option in the picker. */\nexport const CRAFT_SKILL_KIND_DESCRIPTIONS: Record<CraftSkillKind, string> = {\n original: 'Entirely your own original creation.',\n mimicOnTtt: 'Your performance or recreation of another member’s TTT work (link the source).',\n mimicOffTtt: 'A cover or recreation of work from outside TTT (including public-domain works).',\n};\n\nexport const CRAFT_SKILL_STATEMENTS: Record<CraftSkillKind, string> = {\n original:\n 'I certify this craft skill is entirely my own original creation and I own all rights to it. No part of it copies or imitates another person’s work.',\n mimicOnTtt:\n 'This craft skill is my performance or recreation of work created by a member of the TTT Productions community, shown here to demonstrate my abilities. I have linked the original artisan or work below. The original work belongs to its creator, and I claim no ownership of it.',\n mimicOffTtt:\n 'This craft skill is my performance or recreation of a work that did not originate on TTT Productions (including public-domain or out-of-copyright works), shown only to demonstrate my abilities. The underlying work belongs to its owner, and I claim no ownership of it. I understand TTT Productions may remove this content at any time, including in response to a rights-holder request.',\n};\n\nexport const CRAFT_SKILL_KIND_ORDER: CraftSkillKind[] = ['original', 'mimicOnTtt', 'mimicOffTtt'];\n\n/**\n * Why \"Mimicked work from outside TTT Productions\" cannot be chosen yet: the picker shows it\n * when a person selects that kind, and the upload callable refuses the kind with the same words.\n */\nexport const CRAFT_SKILL_MIMIC_OFF_TTT_UNAVAILABLE_MESSAGE =\n \"This option isn't available yet: sharing covers or recreations of work from outside TTT needs legal review first.\";\n\n/**\n * The ONE owner of which craft kinds are blocked at launch, with each one's refusal copy. A\n * blocked kind still renders in the picker (so people see it is coming) but selecting it stops\n * the flow with this copy, and the upload callable refuses it with the same words. Unblocking a\n * kind is removing its entry here.\n */\nexport const CRAFT_SKILL_KIND_UNAVAILABLE_MESSAGES = {\n mimicOffTtt: CRAFT_SKILL_MIMIC_OFF_TTT_UNAVAILABLE_MESSAGE,\n} as const satisfies Partial<Record<CraftSkillKind, string>>;\n\n/** A craft kind that is blocked at launch. */\nexport type BlockedCraftSkillKind = keyof typeof CRAFT_SKILL_KIND_UNAVAILABLE_MESSAGES;\n\n/** Every craft kind blocked at launch — derived from the refusal copy, never restated. */\nexport const BLOCKED_CRAFT_SKILL_KINDS = Object.keys(\n CRAFT_SKILL_KIND_UNAVAILABLE_MESSAGES,\n) as readonly BlockedCraftSkillKind[];\n\n/** True when `kind` is blocked at launch; narrows it to index its refusal copy. */\nexport function isBlockedCraftSkillKind(kind: CraftSkillKind): kind is BlockedCraftSkillKind {\n return Object.prototype.hasOwnProperty.call(CRAFT_SKILL_KIND_UNAVAILABLE_MESSAGES, kind);\n}\n"]}
|
|
@@ -54,6 +54,9 @@ export declare const LEGAL_REVIEW_NOTICE_PLACEMENTS: {
|
|
|
54
54
|
readonly artisanCreatorUpgrade: readonly ["inline", "strip"];
|
|
55
55
|
/** Craft-skill upload, beside its agreement. */
|
|
56
56
|
readonly craftSkillUpload: readonly ["inline", "strip"];
|
|
57
|
+
/** An Artisan submitting an Audition entry — a compact strip beside Submit Entry (the launch
|
|
58
|
+
* mascot Auditions hand their winning art to TTT). */
|
|
59
|
+
readonly auditionEntrySubmission: readonly ["strip"];
|
|
57
60
|
/** Square first post, beside its agreement. */
|
|
58
61
|
readonly squareStreetzFirstPost: readonly ["inline", "strip"];
|
|
59
62
|
/** Guild invite agreements. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legal-review-notice.d.ts","sourceRoot":"","sources":["../../src/constants/legal-review-notice.ts"],"names":[],"mappings":"AAkBA,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEtF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AAItF,iFAAiF;AACjF,MAAM,MAAM,2BAA2B,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAE3E,6EAA6E;AAC7E,MAAM,MAAM,wBAAwB,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;CAAE,CAAC;AAIpG,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,mCAAmC,CAAC;AAE5E,4BAA4B;AAC5B,eAAO,MAAM,wBAAwB,QAMuC,CAAC;AAE7E,mEAAmE;AACnE,eAAO,MAAM,8BAA8B,EAAE,SAAS,wBAAwB,EAG7E,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,4BAA4B,QAE2B,CAAC;AAqBrE,wGAAwG;AACxG,wBAAgB,kCAAkC,IAAI,SAAS,wBAAwB,EAAE,CAIxF;AAID;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,kDAAmD,CAAC;AAC7F,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC;AAIrF;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B;IACzC;6FACyF;;IAEzF,mEAAmE;;IAEnE,wEAAwE;;IAExE,iGAAiG;;IAEjG,oGAAoG;;IAEpG,mDAAmD;;IAEnD,6CAA6C;;IAE7C,gDAAgD;;IAEhD,+CAA+C;;IAE/C,+BAA+B;;IAE/B,gDAAgD;;IAEhD,oCAAoC;;IAEpC,0CAA0C;;IAE1C,8CAA8C;;IAE9C,0BAA0B;;IAE1B,4BAA4B;;IAE5B,uBAAuB;;CAEwC,CAAC;AAElE,uCAAuC;AACvC,MAAM,MAAM,wBAAwB,GAAG,MAAM,OAAO,8BAA8B,CAAC;AAEnF,iDAAiD;AACjD,MAAM,MAAM,2BAA2B,CAAC,CAAC,SAAS,wBAAwB,IACxE,CAAC,OAAO,8BAA8B,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,eAAO,MAAM,4BAA4B,EAEpC,wBAAwB,EAAE,CAAC;AAYhC;;;GAGG;AACH,wBAAgB,sCAAsC,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAE5F;AAID,4EAA4E;AAC5E,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,wBAAwB,EAAE,GAAG,MAAM,CAEnG;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,wBAAwB,EAC3E,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,2BAA2B,CAAC,CAAC,CAAC,GACvC,MAAM,GAAG,IAAI,CAgBf;AAID,gGAAgG;AAChG,wBAAgB,+BAA+B,IAAI,MAAM,GAAG,IAAI,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAGrG"}
|
|
1
|
+
{"version":3,"file":"legal-review-notice.d.ts","sourceRoot":"","sources":["../../src/constants/legal-review-notice.ts"],"names":[],"mappings":"AAkBA,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEtF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AAItF,iFAAiF;AACjF,MAAM,MAAM,2BAA2B,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAE3E,6EAA6E;AAC7E,MAAM,MAAM,wBAAwB,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;CAAE,CAAC;AAIpG,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,mCAAmC,CAAC;AAE5E,4BAA4B;AAC5B,eAAO,MAAM,wBAAwB,QAMuC,CAAC;AAE7E,mEAAmE;AACnE,eAAO,MAAM,8BAA8B,EAAE,SAAS,wBAAwB,EAG7E,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,4BAA4B,QAE2B,CAAC;AAqBrE,wGAAwG;AACxG,wBAAgB,kCAAkC,IAAI,SAAS,wBAAwB,EAAE,CAIxF;AAID;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,kDAAmD,CAAC;AAC7F,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC;AAIrF;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B;IACzC;6FACyF;;IAEzF,mEAAmE;;IAEnE,wEAAwE;;IAExE,iGAAiG;;IAEjG,oGAAoG;;IAEpG,mDAAmD;;IAEnD,6CAA6C;;IAE7C,gDAAgD;;IAEhD;2DACuD;;IAEvD,+CAA+C;;IAE/C,+BAA+B;;IAE/B,gDAAgD;;IAEhD,oCAAoC;;IAEpC,0CAA0C;;IAE1C,8CAA8C;;IAE9C,0BAA0B;;IAE1B,4BAA4B;;IAE5B,uBAAuB;;CAEwC,CAAC;AAElE,uCAAuC;AACvC,MAAM,MAAM,wBAAwB,GAAG,MAAM,OAAO,8BAA8B,CAAC;AAEnF,iDAAiD;AACjD,MAAM,MAAM,2BAA2B,CAAC,CAAC,SAAS,wBAAwB,IACxE,CAAC,OAAO,8BAA8B,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,eAAO,MAAM,4BAA4B,EAEpC,wBAAwB,EAAE,CAAC;AAYhC;;;GAGG;AACH,wBAAgB,sCAAsC,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAE5F;AAID,4EAA4E;AAC5E,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,wBAAwB,EAAE,GAAG,MAAM,CAEnG;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,wBAAwB,EAC3E,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,2BAA2B,CAAC,CAAC,CAAC,GACvC,MAAM,GAAG,IAAI,CAgBf;AAID,gGAAgG;AAChG,wBAAgB,+BAA+B,IAAI,MAAM,GAAG,IAAI,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAGrG"}
|
|
@@ -90,6 +90,9 @@ export const LEGAL_REVIEW_NOTICE_PLACEMENTS = {
|
|
|
90
90
|
artisanCreatorUpgrade: ['inline', 'strip'],
|
|
91
91
|
/** Craft-skill upload, beside its agreement. */
|
|
92
92
|
craftSkillUpload: ['inline', 'strip'],
|
|
93
|
+
/** An Artisan submitting an Audition entry — a compact strip beside Submit Entry (the launch
|
|
94
|
+
* mascot Auditions hand their winning art to TTT). */
|
|
95
|
+
auditionEntrySubmission: ['strip'],
|
|
93
96
|
/** Square first post, beside its agreement. */
|
|
94
97
|
squareStreetzFirstPost: ['inline', 'strip'],
|
|
95
98
|
/** Guild invite agreements. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legal-review-notice.js","sourceRoot":"","sources":["../../src/constants/legal-review-notice.ts"],"names":[],"mappings":"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","sourcesContent":["// ============================================================================\n// FOUNDER LEGAL-REVIEW NOTICE — the ONE owner of the notice copy, its placements,\n// and the plain-text helper for backend-owned copy. The on/off switch and the\n// immutable revision id live in ./legal-review-notice-state.ts.\n//\n// TTT's public pages were written by the founder before any legal review. The\n// notice says so wherever people read policy, create accounts, upload, publish,\n// or pledge. The app renders it through one component,\n// `<LegalReviewNotice context=… variant=… />`; nothing restates these words or\n// keeps a local flag.\n//\n// Copy is settled and verbatim — never reword it in place. A wording change is a\n// new LEGAL_REVIEW_NOTICE_REVISION (the package test pins each revision's copy).\n// Links are semantic targets, not URLs: a public document id, or the founder's\n// note itself; the app maps them to routes or its note dialog.\n// ============================================================================\n\nimport { SPECIAL_DOCS } from '../paths/collections.js';\nimport { PUBLIC_DOCUMENT_LABELS, type PublicDocumentId } from './public-documents.js';\nimport { LEGAL_REVIEW_NOTICE_ACTIVE, LEGAL_REVIEW_NOTICE_REVISION } from './legal-review-notice-state.js';\nimport type { LegalReviewNoticeReceipt } from '../doc-schemas/legal-review-notice.js';\n\n// ── Copy model ───────────────────────────────────────────────────────────────\n\n/** Where a notice link points: a public document, or the founder's full note. */\nexport type LegalReviewNoticeLinkTarget = PublicDocumentId | 'founderNote';\n\n/** One run of notice copy. A link carries a semantic target, never a URL. */\nexport type LegalReviewNoticeSegment =\n | { readonly kind: 'text'; readonly text: string }\n | { readonly kind: 'link'; readonly label: string; readonly target: LegalReviewNoticeLinkTarget };\n\n// ── The settled copy ─────────────────────────────────────────────────────────\n\n/** The full note's heading (the note's first sentence). */\nexport const LEGAL_REVIEW_NOTICE_HEADING = \"A note from DJ, TTT's founder.\";\n\n/** The full note's body. */\nexport const LEGAL_REVIEW_NOTICE_BODY =\n \"These pages describe how I intend TTT to work: my principles and what I'm trying to build. \" +\n 'I wrote them myself, with help from AI tools, before I could afford a lawyer, so none of it ' +\n \"has had legal review, and I honestly don't know whether all of it is legally sound. Charter \" +\n \"Season support keeps TTT running first; after that, it's how I'll get a lawyer to turn this \" +\n 'into real, reviewed legal wording. The words may change when that happens. My intentions ' +\n \"won't. If a change needs your agreement, I'll ask you before it applies.\";\n\n/** The short line. Its closing sentence links to the full note. */\nexport const LEGAL_REVIEW_NOTICE_SHORT_LINE: readonly LegalReviewNoticeSegment[] = [\n { kind: 'text', text: \"TTT's terms are my intentions, written by me and not yet reviewed by a lawyer. \" },\n { kind: 'link', label: \"Read the founder's note.\", target: 'founderNote' },\n];\n\n/** The required acknowledgment checkbox (Hall submission, pledge). */\nexport const LEGAL_REVIEW_NOTICE_CHECKBOX =\n \"I understand TTT's terms express the founder's intentions, have not had legal review, and \" +\n 'will be updated once Charter Season support makes that possible.';\n\n// The registration Terms checkbox. While the notice is active it carries the notice clause;\n// otherwise it is the plain agreement. Both link the two documents by their canonical labels.\nconst REGISTRATION_TERMS_AGREEMENT_LEAD: readonly LegalReviewNoticeSegment[] = [\n { kind: 'text', text: 'I have read and agree to the ' },\n { kind: 'link', label: PUBLIC_DOCUMENT_LABELS[SPECIAL_DOCS.TERMS_PAGE], target: SPECIAL_DOCS.TERMS_PAGE },\n { kind: 'text', text: ' and ' },\n { kind: 'link', label: PUBLIC_DOCUMENT_LABELS[SPECIAL_DOCS.PRIVACY_PAGE], target: SPECIAL_DOCS.PRIVACY_PAGE },\n];\n\nconst REGISTRATION_TERMS_AGREEMENT_WITH_NOTICE: readonly LegalReviewNoticeSegment[] = [\n ...REGISTRATION_TERMS_AGREEMENT_LEAD,\n { kind: 'text', text: \", and I understand they express the founder's intentions and have not had legal review.\" },\n];\n\nconst REGISTRATION_TERMS_AGREEMENT_WITHOUT_NOTICE: readonly LegalReviewNoticeSegment[] = [\n ...REGISTRATION_TERMS_AGREEMENT_LEAD,\n { kind: 'text', text: '.' },\n];\n\n/** The registration Terms checkbox label, with the notice clause exactly while the notice is active. */\nexport function registrationTermsAgreementSegments(): readonly LegalReviewNoticeSegment[] {\n return LEGAL_REVIEW_NOTICE_ACTIVE\n ? REGISTRATION_TERMS_AGREEMENT_WITH_NOTICE\n : REGISTRATION_TERMS_AGREEMENT_WITHOUT_NOTICE;\n}\n\n// ── Variants and placements ──────────────────────────────────────────────────\n\n/**\n * How the notice renders:\n * - `inline` — the short line, in the flow of surrounding text;\n * - `strip` — the short line as a compact strip;\n * - `card` — the full note (heading + body);\n * - `checkbox` — the required acknowledgment checkbox.\n */\nexport const LEGAL_REVIEW_NOTICE_VARIANTS = ['inline', 'strip', 'card', 'checkbox'] as const;\nexport type LegalReviewNoticeVariant = (typeof LEGAL_REVIEW_NOTICE_VARIANTS)[number];\n\ntype LegalReviewNoticeVariantList = readonly [LegalReviewNoticeVariant, ...LegalReviewNoticeVariant[]];\n\n/**\n * Every placement of the notice and the variants it may render (the first is its default).\n * The keys ARE the typed context union. Take It Down and the DMCA policy are statutory\n * processes and carry no notice, so they have no context\n * (see `publicDocumentCarriesLegalReviewNotice`).\n */\nexport const LEGAL_REVIEW_NOTICE_PLACEMENTS = {\n /** Terms, Privacy, Rules & Agreements, Future Plans — beside the current content, rendered at\n * display time (never stored in the document body); also the Admin editors' preview. */\n publicDocument: ['strip'],\n /** Registration — the full note above the agreement checkboxes. */\n registration: ['card'],\n /** The \"Our stuff has changed\" re-acceptance prompt — the full note. */\n reacceptance: ['card'],\n /** Pledge checkout — a compact explanation plus a separate required checkbox on every pledge. */\n pledge: ['strip', 'checkbox'],\n /** Hall submission — a required checkbox in the publish attestations, above Submit for Approval. */\n publish: ['checkbox'],\n /** Work / Realm creation, beside its agreement. */\n workProjectCreation: ['inline', 'strip'],\n /** Artisan upgrade, beside its agreement. */\n artisanCreatorUpgrade: ['inline', 'strip'],\n /** Craft-skill upload, beside its agreement. */\n craftSkillUpload: ['inline', 'strip'],\n /** Square first post, beside its agreement. */\n squareStreetzFirstPost: ['inline', 'strip'],\n /** Guild invite agreements. */\n guildInviteAgreement: ['inline', 'strip'],\n /** Hall download, beside its acknowledgment. */\n hallDownload: ['inline', 'strip'],\n /** The Charter Season explainer. */\n charterExplainer: ['inline', 'card'],\n /** The landing page's founder section. */\n landingFounder: ['inline', 'card'],\n /** The landing page's fundraising section. */\n landingFundraising: ['inline', 'card'],\n /** Stake explanations. */\n stakeShareExplanation: ['inline', 'card'],\n /** Bouquet explanations. */\n bouquetAppreciationExplanation: ['inline', 'card'],\n /** The site footer. */\n footer: ['inline'],\n} as const satisfies Record<string, LegalReviewNoticeVariantList>;\n\n/** A named placement of the notice. */\nexport type LegalReviewNoticeContext = keyof typeof LEGAL_REVIEW_NOTICE_PLACEMENTS;\n\n/** The variants a given placement may render. */\nexport type LegalReviewNoticeVariantFor<C extends LegalReviewNoticeContext> =\n (typeof LEGAL_REVIEW_NOTICE_PLACEMENTS)[C][number];\n\nexport const LEGAL_REVIEW_NOTICE_CONTEXTS = Object.keys(\n LEGAL_REVIEW_NOTICE_PLACEMENTS,\n) as LegalReviewNoticeContext[];\n\nconst PUBLIC_DOCUMENT_CARRIES_NOTICE: Record<PublicDocumentId, boolean> = {\n [SPECIAL_DOCS.TERMS_PAGE]: true,\n [SPECIAL_DOCS.PRIVACY_PAGE]: true,\n [SPECIAL_DOCS.RULES_AND_AGREEMENTS]: true,\n [SPECIAL_DOCS.FUTURE_PLANS]: true,\n // Statutory processes run as built.\n [SPECIAL_DOCS.DMCA_POLICY]: false,\n [SPECIAL_DOCS.TAKE_IT_DOWN_PAGE_COPY]: false,\n};\n\n/**\n * Whether a public document's page (and its Admin editor preview) shows the `publicDocument`\n * notice strip. A placement fact only — the notice itself still renders nothing while off.\n */\nexport function publicDocumentCarriesLegalReviewNotice(documentId: PublicDocumentId): boolean {\n return PUBLIC_DOCUMENT_CARRIES_NOTICE[documentId];\n}\n\n// ── Plain text (backend-owned copy) ──────────────────────────────────────────\n\n/** Flatten segments to plain text: text as written, a link as its label. */\nexport function legalReviewNoticeSegmentsText(segments: readonly LegalReviewNoticeSegment[]): string {\n return segments.map((segment) => (segment.kind === 'text' ? segment.text : segment.label)).join('');\n}\n\n/**\n * The notice as plain text for a placement, for backend-owned copy (a Stripe description, an\n * email). `null` while the notice is off. `variant` defaults to the placement's first variant;\n * a variant the placement does not render throws.\n */\nexport function legalReviewNoticePlainText<C extends LegalReviewNoticeContext>(\n context: C,\n variant?: LegalReviewNoticeVariantFor<C>,\n): string | null {\n if (!LEGAL_REVIEW_NOTICE_ACTIVE) return null;\n const allowed: readonly LegalReviewNoticeVariant[] = LEGAL_REVIEW_NOTICE_PLACEMENTS[context];\n const chosen: LegalReviewNoticeVariant = variant ?? allowed[0];\n if (!allowed.includes(chosen)) {\n throw new Error(`The ${context} notice placement does not render the ${chosen} variant.`);\n }\n switch (chosen) {\n case 'inline':\n case 'strip':\n return legalReviewNoticeSegmentsText(LEGAL_REVIEW_NOTICE_SHORT_LINE);\n case 'card':\n return `${LEGAL_REVIEW_NOTICE_HEADING} ${LEGAL_REVIEW_NOTICE_BODY}`;\n case 'checkbox':\n return LEGAL_REVIEW_NOTICE_CHECKBOX;\n }\n}\n\n// ── What gets recorded ───────────────────────────────────────────────────────\n\n/** The revision a server records with an acceptance or acknowledgment now; `null` while off. */\nexport function activeLegalReviewNoticeRevision(): string | null {\n return LEGAL_REVIEW_NOTICE_ACTIVE ? LEGAL_REVIEW_NOTICE_REVISION : null;\n}\n\n/**\n * The receipt a server records when a person acknowledges the notice (pledge evidence, the Hall\n * threshold item): the active revision and the server time. `null` while the notice is off —\n * nothing is required, so nothing is recorded.\n */\nexport function buildLegalReviewNoticeReceipt(acknowledgedAt: number): LegalReviewNoticeReceipt | null {\n const revision = activeLegalReviewNoticeRevision();\n return revision === null ? null : { revision, acknowledgedAt };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"legal-review-notice.js","sourceRoot":"","sources":["../../src/constants/legal-review-notice.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kFAAkF;AAClF,8EAA8E;AAC9E,gEAAgE;AAChE,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,uDAAuD;AACvD,+EAA+E;AAC/E,sBAAsB;AACtB,EAAE;AACF,iFAAiF;AACjF,iFAAiF;AACjF,+EAA+E;AAC/E,+DAA+D;AAC/D,+EAA+E;AAE/E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAyB,MAAM,uBAAuB,CAAC;AACtF,OAAO,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAa1G,gFAAgF;AAEhF,2DAA2D;AAC3D,MAAM,CAAC,MAAM,2BAA2B,GAAG,gCAAgC,CAAC;AAE5E,4BAA4B;AAC5B,MAAM,CAAC,MAAM,wBAAwB,GACnC,6FAA6F;IAC7F,8FAA8F;IAC9F,8FAA8F;IAC9F,8FAA8F;IAC9F,2FAA2F;IAC3F,0EAA0E,CAAC;AAE7E,mEAAmE;AACnE,MAAM,CAAC,MAAM,8BAA8B,GAAwC;IACjF,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iFAAiF,EAAE;IACzG,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,0BAA0B,EAAE,MAAM,EAAE,aAAa,EAAE;CAC3E,CAAC;AAEF,sEAAsE;AACtE,MAAM,CAAC,MAAM,4BAA4B,GACvC,4FAA4F;IAC5F,kEAAkE,CAAC;AAErE,4FAA4F;AAC5F,8FAA8F;AAC9F,MAAM,iCAAiC,GAAwC;IAC7E,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,+BAA+B,EAAE;IACvD,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,UAAU,EAAE;IACzG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE;IAC/B,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,YAAY,EAAE;CAC9G,CAAC;AAEF,MAAM,wCAAwC,GAAwC;IACpF,GAAG,iCAAiC;IACpC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,yFAAyF,EAAE;CAClH,CAAC;AAEF,MAAM,2CAA2C,GAAwC;IACvF,GAAG,iCAAiC;IACpC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE;CAC5B,CAAC;AAEF,wGAAwG;AACxG,MAAM,UAAU,kCAAkC;IAChD,OAAO,0BAA0B;QAC/B,CAAC,CAAC,wCAAwC;QAC1C,CAAC,CAAC,2CAA2C,CAAC;AAClD,CAAC;AAED,gFAAgF;AAEhF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAU,CAAC;AAK7F;;;;;GAKG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C;6FACyF;IACzF,cAAc,EAAE,CAAC,OAAO,CAAC;IACzB,mEAAmE;IACnE,YAAY,EAAE,CAAC,MAAM,CAAC;IACtB,wEAAwE;IACxE,YAAY,EAAE,CAAC,MAAM,CAAC;IACtB,iGAAiG;IACjG,MAAM,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,oGAAoG;IACpG,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,mDAAmD;IACnD,mBAAmB,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;IACxC,6CAA6C;IAC7C,qBAAqB,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC1C,gDAAgD;IAChD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;IACrC;2DACuD;IACvD,uBAAuB,EAAE,CAAC,OAAO,CAAC;IAClC,+CAA+C;IAC/C,sBAAsB,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3C,+BAA+B;IAC/B,oBAAoB,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;IACzC,gDAAgD;IAChD,YAAY,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;IACjC,oCAAoC;IACpC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;IACpC,0CAA0C;IAC1C,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;IAClC,8CAA8C;IAC9C,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;IACtC,0BAA0B;IAC1B,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;IACzC,4BAA4B;IAC5B,8BAA8B,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;IAClD,uBAAuB;IACvB,MAAM,EAAE,CAAC,QAAQ,CAAC;CAC6C,CAAC;AASlE,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC,IAAI,CACrD,8BAA8B,CACD,CAAC;AAEhC,MAAM,8BAA8B,GAAsC;IACxE,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,IAAI;IAC/B,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,IAAI;IACjC,CAAC,YAAY,CAAC,oBAAoB,CAAC,EAAE,IAAI;IACzC,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,IAAI;IACjC,oCAAoC;IACpC,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,KAAK;IACjC,CAAC,YAAY,CAAC,sBAAsB,CAAC,EAAE,KAAK;CAC7C,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,sCAAsC,CAAC,UAA4B;IACjF,OAAO,8BAA8B,CAAC,UAAU,CAAC,CAAC;AACpD,CAAC;AAED,gFAAgF;AAEhF,4EAA4E;AAC5E,MAAM,UAAU,6BAA6B,CAAC,QAA6C;IACzF,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACtG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAU,EACV,OAAwC;IAExC,IAAI,CAAC,0BAA0B;QAAE,OAAO,IAAI,CAAC;IAC7C,MAAM,OAAO,GAAwC,8BAA8B,CAAC,OAAO,CAAC,CAAC;IAC7F,MAAM,MAAM,GAA6B,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/D,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,OAAO,OAAO,yCAAyC,MAAM,WAAW,CAAC,CAAC;IAC5F,CAAC;IACD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO;YACV,OAAO,6BAA6B,CAAC,8BAA8B,CAAC,CAAC;QACvE,KAAK,MAAM;YACT,OAAO,GAAG,2BAA2B,IAAI,wBAAwB,EAAE,CAAC;QACtE,KAAK,UAAU;YACb,OAAO,4BAA4B,CAAC;IACxC,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,gGAAgG;AAChG,MAAM,UAAU,+BAA+B;IAC7C,OAAO,0BAA0B,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,cAAsB;IAClE,MAAM,QAAQ,GAAG,+BAA+B,EAAE,CAAC;IACnD,OAAO,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AACjE,CAAC","sourcesContent":["// ============================================================================\n// FOUNDER LEGAL-REVIEW NOTICE — the ONE owner of the notice copy, its placements,\n// and the plain-text helper for backend-owned copy. The on/off switch and the\n// immutable revision id live in ./legal-review-notice-state.ts.\n//\n// TTT's public pages were written by the founder before any legal review. The\n// notice says so wherever people read policy, create accounts, upload, publish,\n// or pledge. The app renders it through one component,\n// `<LegalReviewNotice context=… variant=… />`; nothing restates these words or\n// keeps a local flag.\n//\n// Copy is settled and verbatim — never reword it in place. A wording change is a\n// new LEGAL_REVIEW_NOTICE_REVISION (the package test pins each revision's copy).\n// Links are semantic targets, not URLs: a public document id, or the founder's\n// note itself; the app maps them to routes or its note dialog.\n// ============================================================================\n\nimport { SPECIAL_DOCS } from '../paths/collections.js';\nimport { PUBLIC_DOCUMENT_LABELS, type PublicDocumentId } from './public-documents.js';\nimport { LEGAL_REVIEW_NOTICE_ACTIVE, LEGAL_REVIEW_NOTICE_REVISION } from './legal-review-notice-state.js';\nimport type { LegalReviewNoticeReceipt } from '../doc-schemas/legal-review-notice.js';\n\n// ── Copy model ───────────────────────────────────────────────────────────────\n\n/** Where a notice link points: a public document, or the founder's full note. */\nexport type LegalReviewNoticeLinkTarget = PublicDocumentId | 'founderNote';\n\n/** One run of notice copy. A link carries a semantic target, never a URL. */\nexport type LegalReviewNoticeSegment =\n | { readonly kind: 'text'; readonly text: string }\n | { readonly kind: 'link'; readonly label: string; readonly target: LegalReviewNoticeLinkTarget };\n\n// ── The settled copy ─────────────────────────────────────────────────────────\n\n/** The full note's heading (the note's first sentence). */\nexport const LEGAL_REVIEW_NOTICE_HEADING = \"A note from DJ, TTT's founder.\";\n\n/** The full note's body. */\nexport const LEGAL_REVIEW_NOTICE_BODY =\n \"These pages describe how I intend TTT to work: my principles and what I'm trying to build. \" +\n 'I wrote them myself, with help from AI tools, before I could afford a lawyer, so none of it ' +\n \"has had legal review, and I honestly don't know whether all of it is legally sound. Charter \" +\n \"Season support keeps TTT running first; after that, it's how I'll get a lawyer to turn this \" +\n 'into real, reviewed legal wording. The words may change when that happens. My intentions ' +\n \"won't. If a change needs your agreement, I'll ask you before it applies.\";\n\n/** The short line. Its closing sentence links to the full note. */\nexport const LEGAL_REVIEW_NOTICE_SHORT_LINE: readonly LegalReviewNoticeSegment[] = [\n { kind: 'text', text: \"TTT's terms are my intentions, written by me and not yet reviewed by a lawyer. \" },\n { kind: 'link', label: \"Read the founder's note.\", target: 'founderNote' },\n];\n\n/** The required acknowledgment checkbox (Hall submission, pledge). */\nexport const LEGAL_REVIEW_NOTICE_CHECKBOX =\n \"I understand TTT's terms express the founder's intentions, have not had legal review, and \" +\n 'will be updated once Charter Season support makes that possible.';\n\n// The registration Terms checkbox. While the notice is active it carries the notice clause;\n// otherwise it is the plain agreement. Both link the two documents by their canonical labels.\nconst REGISTRATION_TERMS_AGREEMENT_LEAD: readonly LegalReviewNoticeSegment[] = [\n { kind: 'text', text: 'I have read and agree to the ' },\n { kind: 'link', label: PUBLIC_DOCUMENT_LABELS[SPECIAL_DOCS.TERMS_PAGE], target: SPECIAL_DOCS.TERMS_PAGE },\n { kind: 'text', text: ' and ' },\n { kind: 'link', label: PUBLIC_DOCUMENT_LABELS[SPECIAL_DOCS.PRIVACY_PAGE], target: SPECIAL_DOCS.PRIVACY_PAGE },\n];\n\nconst REGISTRATION_TERMS_AGREEMENT_WITH_NOTICE: readonly LegalReviewNoticeSegment[] = [\n ...REGISTRATION_TERMS_AGREEMENT_LEAD,\n { kind: 'text', text: \", and I understand they express the founder's intentions and have not had legal review.\" },\n];\n\nconst REGISTRATION_TERMS_AGREEMENT_WITHOUT_NOTICE: readonly LegalReviewNoticeSegment[] = [\n ...REGISTRATION_TERMS_AGREEMENT_LEAD,\n { kind: 'text', text: '.' },\n];\n\n/** The registration Terms checkbox label, with the notice clause exactly while the notice is active. */\nexport function registrationTermsAgreementSegments(): readonly LegalReviewNoticeSegment[] {\n return LEGAL_REVIEW_NOTICE_ACTIVE\n ? REGISTRATION_TERMS_AGREEMENT_WITH_NOTICE\n : REGISTRATION_TERMS_AGREEMENT_WITHOUT_NOTICE;\n}\n\n// ── Variants and placements ──────────────────────────────────────────────────\n\n/**\n * How the notice renders:\n * - `inline` — the short line, in the flow of surrounding text;\n * - `strip` — the short line as a compact strip;\n * - `card` — the full note (heading + body);\n * - `checkbox` — the required acknowledgment checkbox.\n */\nexport const LEGAL_REVIEW_NOTICE_VARIANTS = ['inline', 'strip', 'card', 'checkbox'] as const;\nexport type LegalReviewNoticeVariant = (typeof LEGAL_REVIEW_NOTICE_VARIANTS)[number];\n\ntype LegalReviewNoticeVariantList = readonly [LegalReviewNoticeVariant, ...LegalReviewNoticeVariant[]];\n\n/**\n * Every placement of the notice and the variants it may render (the first is its default).\n * The keys ARE the typed context union. Take It Down and the DMCA policy are statutory\n * processes and carry no notice, so they have no context\n * (see `publicDocumentCarriesLegalReviewNotice`).\n */\nexport const LEGAL_REVIEW_NOTICE_PLACEMENTS = {\n /** Terms, Privacy, Rules & Agreements, Future Plans — beside the current content, rendered at\n * display time (never stored in the document body); also the Admin editors' preview. */\n publicDocument: ['strip'],\n /** Registration — the full note above the agreement checkboxes. */\n registration: ['card'],\n /** The \"Our stuff has changed\" re-acceptance prompt — the full note. */\n reacceptance: ['card'],\n /** Pledge checkout — a compact explanation plus a separate required checkbox on every pledge. */\n pledge: ['strip', 'checkbox'],\n /** Hall submission — a required checkbox in the publish attestations, above Submit for Approval. */\n publish: ['checkbox'],\n /** Work / Realm creation, beside its agreement. */\n workProjectCreation: ['inline', 'strip'],\n /** Artisan upgrade, beside its agreement. */\n artisanCreatorUpgrade: ['inline', 'strip'],\n /** Craft-skill upload, beside its agreement. */\n craftSkillUpload: ['inline', 'strip'],\n /** An Artisan submitting an Audition entry — a compact strip beside Submit Entry (the launch\n * mascot Auditions hand their winning art to TTT). */\n auditionEntrySubmission: ['strip'],\n /** Square first post, beside its agreement. */\n squareStreetzFirstPost: ['inline', 'strip'],\n /** Guild invite agreements. */\n guildInviteAgreement: ['inline', 'strip'],\n /** Hall download, beside its acknowledgment. */\n hallDownload: ['inline', 'strip'],\n /** The Charter Season explainer. */\n charterExplainer: ['inline', 'card'],\n /** The landing page's founder section. */\n landingFounder: ['inline', 'card'],\n /** The landing page's fundraising section. */\n landingFundraising: ['inline', 'card'],\n /** Stake explanations. */\n stakeShareExplanation: ['inline', 'card'],\n /** Bouquet explanations. */\n bouquetAppreciationExplanation: ['inline', 'card'],\n /** The site footer. */\n footer: ['inline'],\n} as const satisfies Record<string, LegalReviewNoticeVariantList>;\n\n/** A named placement of the notice. */\nexport type LegalReviewNoticeContext = keyof typeof LEGAL_REVIEW_NOTICE_PLACEMENTS;\n\n/** The variants a given placement may render. */\nexport type LegalReviewNoticeVariantFor<C extends LegalReviewNoticeContext> =\n (typeof LEGAL_REVIEW_NOTICE_PLACEMENTS)[C][number];\n\nexport const LEGAL_REVIEW_NOTICE_CONTEXTS = Object.keys(\n LEGAL_REVIEW_NOTICE_PLACEMENTS,\n) as LegalReviewNoticeContext[];\n\nconst PUBLIC_DOCUMENT_CARRIES_NOTICE: Record<PublicDocumentId, boolean> = {\n [SPECIAL_DOCS.TERMS_PAGE]: true,\n [SPECIAL_DOCS.PRIVACY_PAGE]: true,\n [SPECIAL_DOCS.RULES_AND_AGREEMENTS]: true,\n [SPECIAL_DOCS.FUTURE_PLANS]: true,\n // Statutory processes run as built.\n [SPECIAL_DOCS.DMCA_POLICY]: false,\n [SPECIAL_DOCS.TAKE_IT_DOWN_PAGE_COPY]: false,\n};\n\n/**\n * Whether a public document's page (and its Admin editor preview) shows the `publicDocument`\n * notice strip. A placement fact only — the notice itself still renders nothing while off.\n */\nexport function publicDocumentCarriesLegalReviewNotice(documentId: PublicDocumentId): boolean {\n return PUBLIC_DOCUMENT_CARRIES_NOTICE[documentId];\n}\n\n// ── Plain text (backend-owned copy) ──────────────────────────────────────────\n\n/** Flatten segments to plain text: text as written, a link as its label. */\nexport function legalReviewNoticeSegmentsText(segments: readonly LegalReviewNoticeSegment[]): string {\n return segments.map((segment) => (segment.kind === 'text' ? segment.text : segment.label)).join('');\n}\n\n/**\n * The notice as plain text for a placement, for backend-owned copy (a Stripe description, an\n * email). `null` while the notice is off. `variant` defaults to the placement's first variant;\n * a variant the placement does not render throws.\n */\nexport function legalReviewNoticePlainText<C extends LegalReviewNoticeContext>(\n context: C,\n variant?: LegalReviewNoticeVariantFor<C>,\n): string | null {\n if (!LEGAL_REVIEW_NOTICE_ACTIVE) return null;\n const allowed: readonly LegalReviewNoticeVariant[] = LEGAL_REVIEW_NOTICE_PLACEMENTS[context];\n const chosen: LegalReviewNoticeVariant = variant ?? allowed[0];\n if (!allowed.includes(chosen)) {\n throw new Error(`The ${context} notice placement does not render the ${chosen} variant.`);\n }\n switch (chosen) {\n case 'inline':\n case 'strip':\n return legalReviewNoticeSegmentsText(LEGAL_REVIEW_NOTICE_SHORT_LINE);\n case 'card':\n return `${LEGAL_REVIEW_NOTICE_HEADING} ${LEGAL_REVIEW_NOTICE_BODY}`;\n case 'checkbox':\n return LEGAL_REVIEW_NOTICE_CHECKBOX;\n }\n}\n\n// ── What gets recorded ───────────────────────────────────────────────────────\n\n/** The revision a server records with an acceptance or acknowledgment now; `null` while off. */\nexport function activeLegalReviewNoticeRevision(): string | null {\n return LEGAL_REVIEW_NOTICE_ACTIVE ? LEGAL_REVIEW_NOTICE_REVISION : null;\n}\n\n/**\n * The receipt a server records when a person acknowledges the notice (pledge evidence, the Hall\n * threshold item): the active revision and the server time. `null` while the notice is off —\n * nothing is required, so nothing is recorded.\n */\nexport function buildLegalReviewNoticeReceipt(acknowledgedAt: number): LegalReviewNoticeReceipt | null {\n const revision = activeLegalReviewNoticeRevision();\n return revision === null ? null : { revision, acknowledgedAt };\n}\n"]}
|
|
@@ -15,6 +15,13 @@ export declare const PUBLIC_DOCUMENTS_ACCEPTED_CLAIM = "docsAccepted";
|
|
|
15
15
|
*/
|
|
16
16
|
export declare const PUBLIC_DOCUMENT_ACCEPTANCE_SOURCES: readonly ["registration", "reacceptance"];
|
|
17
17
|
export type PublicDocumentAcceptanceSource = (typeof PUBLIC_DOCUMENT_ACCEPTANCE_SOURCES)[number];
|
|
18
|
+
/**
|
|
19
|
+
* The re-acceptance prompt's explicit agreement line, shown above its Accept and Log out
|
|
20
|
+
* choices. Verbatim and independent of the founder notice: it shows whether or not the notice
|
|
21
|
+
* is active. What a person accepted is recorded as the document/version pairs the prompt
|
|
22
|
+
* listed, so this line carries no revision of its own.
|
|
23
|
+
*/
|
|
24
|
+
export declare const PUBLIC_DOCUMENTS_REACCEPTANCE_STATEMENT = "By choosing Accept, you agree to the current versions of the documents listed above.";
|
|
18
25
|
/** Versions returned per page by the Admin history read (newest first). */
|
|
19
26
|
export declare const PUBLIC_DOCUMENT_HISTORY_PAGE_LIMIT = 10;
|
|
20
27
|
//# sourceMappingURL=public-documents.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-documents.d.ts","sourceRoot":"","sources":["../../src/constants/public-documents.ts"],"names":[],"mappings":"AAkBA,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,uHAOtB,CAAC;AACX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,2FAA2F;AAC3F,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAOnE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,iBAAiB,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,kCAAkC,2CAA4C,CAAC;AAC5F,MAAM,MAAM,8BAA8B,GAAG,CAAC,OAAO,kCAAkC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjG,2EAA2E;AAC3E,eAAO,MAAM,kCAAkC,KAAK,CAAC"}
|
|
1
|
+
{"version":3,"file":"public-documents.d.ts","sourceRoot":"","sources":["../../src/constants/public-documents.ts"],"names":[],"mappings":"AAkBA,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,uHAOtB,CAAC;AACX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,2FAA2F;AAC3F,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAOnE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,iBAAiB,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,kCAAkC,2CAA4C,CAAC;AAC5F,MAAM,MAAM,8BAA8B,GAAG,CAAC,OAAO,kCAAkC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjG;;;;;GAKG;AACH,eAAO,MAAM,uCAAuC,yFACoC,CAAC;AAEzF,2EAA2E;AAC3E,eAAO,MAAM,kCAAkC,KAAK,CAAC"}
|
|
@@ -43,6 +43,13 @@ export const PUBLIC_DOCUMENTS_ACCEPTED_CLAIM = 'docsAccepted';
|
|
|
43
43
|
* Both write the same private summary and the same `publicDocuments.accepted` audit event.
|
|
44
44
|
*/
|
|
45
45
|
export const PUBLIC_DOCUMENT_ACCEPTANCE_SOURCES = ['registration', 'reacceptance'];
|
|
46
|
+
/**
|
|
47
|
+
* The re-acceptance prompt's explicit agreement line, shown above its Accept and Log out
|
|
48
|
+
* choices. Verbatim and independent of the founder notice: it shows whether or not the notice
|
|
49
|
+
* is active. What a person accepted is recorded as the document/version pairs the prompt
|
|
50
|
+
* listed, so this line carries no revision of its own.
|
|
51
|
+
*/
|
|
52
|
+
export const PUBLIC_DOCUMENTS_REACCEPTANCE_STATEMENT = 'By choosing Accept, you agree to the current versions of the documents listed above.';
|
|
46
53
|
/** Versions returned per page by the Admin history read (newest first). */
|
|
47
54
|
export const PUBLIC_DOCUMENT_HISTORY_PAGE_LIMIT = 10;
|
|
48
55
|
//# sourceMappingURL=public-documents.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-documents.js","sourceRoot":"","sources":["../../src/constants/public-documents.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gFAAgF;AAChF,0EAA0E;AAC1E,8EAA8E;AAC9E,iFAAiF;AACjF,kCAAkC;AAClC,EAAE;AACF,6EAA6E;AAC7E,iFAAiF;AACjF,2DAA2D;AAC3D,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,iEAAiE;AACjE,+EAA+E;AAE/E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,yDAAyD;AACzD,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,YAAY,CAAC,UAAU;IACvB,YAAY,CAAC,YAAY;IACzB,YAAY,CAAC,oBAAoB;IACjC,YAAY,CAAC,YAAY;IACzB,YAAY,CAAC,WAAW;IACxB,YAAY,CAAC,sBAAsB;CAC3B,CAAC;AAGX,2FAA2F;AAC3F,MAAM,CAAC,MAAM,sBAAsB,GAAqC;IACtE,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,kBAAkB;IAC7C,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,gBAAgB;IAC7C,CAAC,YAAY,CAAC,oBAAoB,CAAC,EAAE,oBAAoB;IACzD,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,cAAc;IAC3C,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,aAAa;IACzC,CAAC,YAAY,CAAC,sBAAsB,CAAC,EAAE,cAAc;CACtD,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,cAAc,CAAC;AAE9D;;;GAGG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,cAAc,EAAE,cAAc,CAAU,CAAC;AAG5F,2EAA2E;AAC3E,MAAM,CAAC,MAAM,kCAAkC,GAAG,EAAE,CAAC","sourcesContent":["// ============================================================================\n// PUBLIC DOCUMENTS — the Admin-editable public web pages that are versioned and\n// published in release bundles: Terms of Service, Privacy Policy, Rules &\n// Agreements, Future Plans, the DMCA policy, and the Take It Down explanatory\n// copy. ONE owner for the document identity, display labels, and the numbers the\n// release / acceptance flow uses.\n//\n// Each PublicDocumentId is ALSO the doc id of that document's public current\n// projection under `_appConfig` (PATH_BUILDERS.publicDocumentProjection), so the\n// ids derive from SPECIAL_DOCS rather than being restated.\n//\n// Versions are whole numbers v1, v2, … per document. \"Require acceptance\" is a\n// property of a RELEASE, never a second version number: a release that requires\n// acceptance raises the single required-acceptance level by one.\n// ============================================================================\n\nimport { SPECIAL_DOCS } from '../paths/collections.js';\n\n/** Every public document, in canonical display order. */\nexport const PUBLIC_DOCUMENT_IDS = [\n SPECIAL_DOCS.TERMS_PAGE,\n SPECIAL_DOCS.PRIVACY_PAGE,\n SPECIAL_DOCS.RULES_AND_AGREEMENTS,\n SPECIAL_DOCS.FUTURE_PLANS,\n SPECIAL_DOCS.DMCA_POLICY,\n SPECIAL_DOCS.TAKE_IT_DOWN_PAGE_COPY,\n] as const;\nexport type PublicDocumentId = (typeof PUBLIC_DOCUMENT_IDS)[number];\n\n/** The user-facing name of each public document (Admin list, acceptance prompt, links). */\nexport const PUBLIC_DOCUMENT_LABELS: Record<PublicDocumentId, string> = {\n [SPECIAL_DOCS.TERMS_PAGE]: 'Terms of Service',\n [SPECIAL_DOCS.PRIVACY_PAGE]: 'Privacy Policy',\n [SPECIAL_DOCS.RULES_AND_AGREEMENTS]: 'Rules & Agreements',\n [SPECIAL_DOCS.FUTURE_PLANS]: 'Future Plans',\n [SPECIAL_DOCS.DMCA_POLICY]: 'DMCA Policy',\n [SPECIAL_DOCS.TAKE_IT_DOWN_PAGE_COPY]: 'Take It Down',\n};\n\n/**\n * The custom claim holding the caller's accepted level. Written by the acceptance core\n * (through `updateClaim`) and read by the backend acceptance gate (auth-core's\n * `acceptance.claimKey`) — one name for both sides.\n */\nexport const PUBLIC_DOCUMENTS_ACCEPTED_CLAIM = 'docsAccepted';\n\n/**\n * How an acceptance was recorded: at registration, or through the re-acceptance prompt.\n * Both write the same private summary and the same `publicDocuments.accepted` audit event.\n */\nexport const PUBLIC_DOCUMENT_ACCEPTANCE_SOURCES = ['registration', 'reacceptance'] as const;\nexport type PublicDocumentAcceptanceSource = (typeof PUBLIC_DOCUMENT_ACCEPTANCE_SOURCES)[number];\n\n/** Versions returned per page by the Admin history read (newest first). */\nexport const PUBLIC_DOCUMENT_HISTORY_PAGE_LIMIT = 10;\n"]}
|
|
1
|
+
{"version":3,"file":"public-documents.js","sourceRoot":"","sources":["../../src/constants/public-documents.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gFAAgF;AAChF,0EAA0E;AAC1E,8EAA8E;AAC9E,iFAAiF;AACjF,kCAAkC;AAClC,EAAE;AACF,6EAA6E;AAC7E,iFAAiF;AACjF,2DAA2D;AAC3D,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,iEAAiE;AACjE,+EAA+E;AAE/E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,yDAAyD;AACzD,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,YAAY,CAAC,UAAU;IACvB,YAAY,CAAC,YAAY;IACzB,YAAY,CAAC,oBAAoB;IACjC,YAAY,CAAC,YAAY;IACzB,YAAY,CAAC,WAAW;IACxB,YAAY,CAAC,sBAAsB;CAC3B,CAAC;AAGX,2FAA2F;AAC3F,MAAM,CAAC,MAAM,sBAAsB,GAAqC;IACtE,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,kBAAkB;IAC7C,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,gBAAgB;IAC7C,CAAC,YAAY,CAAC,oBAAoB,CAAC,EAAE,oBAAoB;IACzD,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,cAAc;IAC3C,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,aAAa;IACzC,CAAC,YAAY,CAAC,sBAAsB,CAAC,EAAE,cAAc;CACtD,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,cAAc,CAAC;AAE9D;;;GAGG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,cAAc,EAAE,cAAc,CAAU,CAAC;AAG5F;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uCAAuC,GAClD,sFAAsF,CAAC;AAEzF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,kCAAkC,GAAG,EAAE,CAAC","sourcesContent":["// ============================================================================\n// PUBLIC DOCUMENTS — the Admin-editable public web pages that are versioned and\n// published in release bundles: Terms of Service, Privacy Policy, Rules &\n// Agreements, Future Plans, the DMCA policy, and the Take It Down explanatory\n// copy. ONE owner for the document identity, display labels, and the numbers the\n// release / acceptance flow uses.\n//\n// Each PublicDocumentId is ALSO the doc id of that document's public current\n// projection under `_appConfig` (PATH_BUILDERS.publicDocumentProjection), so the\n// ids derive from SPECIAL_DOCS rather than being restated.\n//\n// Versions are whole numbers v1, v2, … per document. \"Require acceptance\" is a\n// property of a RELEASE, never a second version number: a release that requires\n// acceptance raises the single required-acceptance level by one.\n// ============================================================================\n\nimport { SPECIAL_DOCS } from '../paths/collections.js';\n\n/** Every public document, in canonical display order. */\nexport const PUBLIC_DOCUMENT_IDS = [\n SPECIAL_DOCS.TERMS_PAGE,\n SPECIAL_DOCS.PRIVACY_PAGE,\n SPECIAL_DOCS.RULES_AND_AGREEMENTS,\n SPECIAL_DOCS.FUTURE_PLANS,\n SPECIAL_DOCS.DMCA_POLICY,\n SPECIAL_DOCS.TAKE_IT_DOWN_PAGE_COPY,\n] as const;\nexport type PublicDocumentId = (typeof PUBLIC_DOCUMENT_IDS)[number];\n\n/** The user-facing name of each public document (Admin list, acceptance prompt, links). */\nexport const PUBLIC_DOCUMENT_LABELS: Record<PublicDocumentId, string> = {\n [SPECIAL_DOCS.TERMS_PAGE]: 'Terms of Service',\n [SPECIAL_DOCS.PRIVACY_PAGE]: 'Privacy Policy',\n [SPECIAL_DOCS.RULES_AND_AGREEMENTS]: 'Rules & Agreements',\n [SPECIAL_DOCS.FUTURE_PLANS]: 'Future Plans',\n [SPECIAL_DOCS.DMCA_POLICY]: 'DMCA Policy',\n [SPECIAL_DOCS.TAKE_IT_DOWN_PAGE_COPY]: 'Take It Down',\n};\n\n/**\n * The custom claim holding the caller's accepted level. Written by the acceptance core\n * (through `updateClaim`) and read by the backend acceptance gate (auth-core's\n * `acceptance.claimKey`) — one name for both sides.\n */\nexport const PUBLIC_DOCUMENTS_ACCEPTED_CLAIM = 'docsAccepted';\n\n/**\n * How an acceptance was recorded: at registration, or through the re-acceptance prompt.\n * Both write the same private summary and the same `publicDocuments.accepted` audit event.\n */\nexport const PUBLIC_DOCUMENT_ACCEPTANCE_SOURCES = ['registration', 'reacceptance'] as const;\nexport type PublicDocumentAcceptanceSource = (typeof PUBLIC_DOCUMENT_ACCEPTANCE_SOURCES)[number];\n\n/**\n * The re-acceptance prompt's explicit agreement line, shown above its Accept and Log out\n * choices. Verbatim and independent of the founder notice: it shows whether or not the notice\n * is active. What a person accepted is recorded as the document/version pairs the prompt\n * listed, so this line carries no revision of its own.\n */\nexport const PUBLIC_DOCUMENTS_REACCEPTANCE_STATEMENT =\n 'By choosing Accept, you agree to the current versions of the documents listed above.';\n\n/** Versions returned per page by the Admin history read (newest first). */\nexport const PUBLIC_DOCUMENT_HISTORY_PAGE_LIMIT = 10;\n"]}
|
|
@@ -2,10 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
/** Blocked-hash retention policy — indefinite until an appeal reverses it. */
|
|
3
3
|
export declare const NciiBlockedHashRetentionPolicySchema: z.ZodLiteral<"indefiniteUntilReversed">;
|
|
4
4
|
export type NciiBlockedHashRetentionPolicy = z.infer<typeof NciiBlockedHashRetentionPolicySchema>;
|
|
5
|
-
/** `_serverData/nciiPolicy` = `NciiPolicyConfigV1` — the
|
|
6
|
-
* Counsel ratifies (`counselApproved`) at the pre-launch gate; uploads stay
|
|
7
|
-
* blocked until then. Any value missing/placeholder → the launch audit FAILS
|
|
8
|
-
* CLOSED. */
|
|
5
|
+
/** `_serverData/nciiPolicy` = `NciiPolicyConfigV1` — the operator launch defaults. */
|
|
9
6
|
export declare const NciiPolicyConfigV1Schema: z.ZodObject<{
|
|
10
7
|
policyVersion: z.ZodLiteral<"ncii.2026-06-23.v1">;
|
|
11
8
|
requesterPiiRetentionDays: z.ZodNumber;
|
|
@@ -33,7 +30,6 @@ export declare const NciiPolicyConfigV1Schema: z.ZodObject<{
|
|
|
33
30
|
evidenceScanMemoryBudgetMb: z.ZodNumber;
|
|
34
31
|
rejectArchiveAndPolyglotPayloads: z.ZodBoolean;
|
|
35
32
|
approvedBy: z.ZodLiteral<"operatorLaunchDefault">;
|
|
36
|
-
counselApproved: z.ZodBoolean;
|
|
37
33
|
}, z.core.$strict>;
|
|
38
34
|
export type NciiPolicyConfigV1 = z.infer<typeof NciiPolicyConfigV1Schema>;
|
|
39
35
|
/** The frozen launch default for `_serverData/nciiPolicy`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/doc-schemas/ncii/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/doc-schemas/ncii/config.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,8EAA8E;AAC9E,eAAO,MAAM,oCAAoC,yCAAuC,CAAC;AACzF,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAElG,sFAAsF;AACtF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAoC1B,CAAC;AACZ,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,8DAA8D;AAC9D,eAAO,MAAM,6BAA6B,EAAE,kBAgC3C,CAAC;AAYF;6CAC6C;AAC7C,eAAO,MAAM,oCAAoC,iCAA+B,CAAC;AACjF,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAElG;qCACqC;AACrC,eAAO,MAAM,uCAAuC;;;;;;;EAOlD,CAAC;AACH,MAAM,MAAM,iCAAiC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uCAAuC,CAAC,CAAC;AAExG;gFACgF;AAChF,eAAO,MAAM,yCAAyC;;;;;;;;;;;;;;;;kBAiB3C,CAAC;AACZ,MAAM,MAAM,mCAAmC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yCAAyC,CAAC,CAAC;AAE5G,8EAA8E;AAC9E,eAAO,MAAM,+CAA+C,EAAE,mCAgB7D,CAAC"}
|
|
@@ -1,26 +1,21 @@
|
|
|
1
1
|
// Trust & Safety — NCII config singletons (Appendix A §A11 [H6] / [H-17] / [H-18]).
|
|
2
2
|
//
|
|
3
|
-
// Two `
|
|
3
|
+
// Two Admin-SDK-only `_serverData` singleton documents, wired into COLLECTIONS,
|
|
4
|
+
// PATH_BUILDERS, and the doc-schema registry:
|
|
4
5
|
// - `_serverData/nciiPolicy` → NciiPolicyConfigV1
|
|
5
6
|
// - `_serverData/privilegedReviewerSecurity` → PrivilegedReviewerSecurityProfileV1
|
|
6
7
|
//
|
|
7
|
-
// These are VERSIONED launch defaults
|
|
8
|
-
//
|
|
9
|
-
// increments the policy version and triggers a retention/configuration review.
|
|
10
|
-
// launch/config audit FAILS CLOSED if any value is missing or a placeholder;
|
|
11
|
-
// uploads stay BLOCKED until `counselApproved` flips true at the pre-launch counsel
|
|
12
|
-
// gate.
|
|
8
|
+
// These are VERSIONED operator launch defaults (`approvedBy: 'operatorLaunchDefault'`);
|
|
9
|
+
// a reader falls back to the frozen DEFAULT when the stored doc is absent. Any change
|
|
10
|
+
// increments the policy version and triggers a retention/configuration review.
|
|
13
11
|
//
|
|
14
12
|
// Every value in the DEFAULT consts below is transcribed verbatim from the frozen
|
|
15
13
|
// Trust & Safety spec (Appendix A §A11 [H6] / [H-17] / [H-18]) — no invented values,
|
|
16
14
|
// no placeholders; the durable design owner is ttt-prod
|
|
17
15
|
// docs/design/nonconsensual-intimate-imagery-and-take-it-down.md. The schemas pin
|
|
18
16
|
// each literal-defaulted field where the spec fixes a single literal value
|
|
19
|
-
// (`policyVersion`, `approvedBy`,
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// Collection note: these are `_config` singleton docs; wiring collections.ts /
|
|
23
|
-
// path-builders.ts / registry.ts is deferred to the app leg.
|
|
17
|
+
// (`policyVersion`, `approvedBy`, the security-profile string literals, etc.) so a
|
|
18
|
+
// config write cannot silently drift from the frozen posture.
|
|
24
19
|
import { z } from 'zod';
|
|
25
20
|
// ===========================================================================
|
|
26
21
|
// §A11 [H6] — NciiPolicyConfigV1 + DEFAULT_NCII_POLICY_CONFIG_V1
|
|
@@ -28,10 +23,7 @@ import { z } from 'zod';
|
|
|
28
23
|
// ===========================================================================
|
|
29
24
|
/** Blocked-hash retention policy — indefinite until an appeal reverses it. */
|
|
30
25
|
export const NciiBlockedHashRetentionPolicySchema = z.literal('indefiniteUntilReversed');
|
|
31
|
-
/** `_serverData/nciiPolicy` = `NciiPolicyConfigV1` — the
|
|
32
|
-
* Counsel ratifies (`counselApproved`) at the pre-launch gate; uploads stay
|
|
33
|
-
* blocked until then. Any value missing/placeholder → the launch audit FAILS
|
|
34
|
-
* CLOSED. */
|
|
26
|
+
/** `_serverData/nciiPolicy` = `NciiPolicyConfigV1` — the operator launch defaults. */
|
|
35
27
|
export const NciiPolicyConfigV1Schema = z.object({
|
|
36
28
|
policyVersion: z.literal('ncii.2026-06-23.v1'),
|
|
37
29
|
requesterPiiRetentionDays: z.number(),
|
|
@@ -68,8 +60,6 @@ export const NciiPolicyConfigV1Schema = z.object({
|
|
|
68
60
|
evidenceScanMemoryBudgetMb: z.number(),
|
|
69
61
|
rejectArchiveAndPolyglotPayloads: z.boolean(),
|
|
70
62
|
approvedBy: z.literal('operatorLaunchDefault'),
|
|
71
|
-
// counselApproved flips true at the pre-launch counsel gate; uploads stay blocked until then
|
|
72
|
-
counselApproved: z.boolean(),
|
|
73
63
|
}).strict();
|
|
74
64
|
/** The frozen launch default for `_serverData/nciiPolicy`. */
|
|
75
65
|
export const DEFAULT_NCII_POLICY_CONFIG_V1 = {
|
|
@@ -104,7 +94,6 @@ export const DEFAULT_NCII_POLICY_CONFIG_V1 = {
|
|
|
104
94
|
evidenceScanMemoryBudgetMb: 512,
|
|
105
95
|
rejectArchiveAndPolyglotPayloads: true,
|
|
106
96
|
approvedBy: 'operatorLaunchDefault',
|
|
107
|
-
counselApproved: false,
|
|
108
97
|
};
|
|
109
98
|
// ===========================================================================
|
|
110
99
|
// §A11 [H-17] — PrivilegedReviewerSecurityProfileV1 +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/doc-schemas/ncii/config.ts"],"names":[],"mappings":"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","sourcesContent":["// Trust & Safety — NCII config singletons (Appendix A §A11 [H6] / [H-17] / [H-18]).\n//\n// Two `_config` singleton documents:\n// - `_serverData/nciiPolicy` → NciiPolicyConfigV1\n// - `_serverData/privilegedReviewerSecurity` → PrivilegedReviewerSecurityProfileV1\n//\n// These are VERSIONED launch defaults. Qualified counsel must approve them before\n// uploads open and may increase, decrease, or otherwise modify them. Any change\n// increments the policy version and triggers a retention/configuration review. The\n// launch/config audit FAILS CLOSED if any value is missing or a placeholder;\n// uploads stay BLOCKED until `counselApproved` flips true at the pre-launch counsel\n// gate.\n//\n// Every value in the DEFAULT consts below is transcribed verbatim from the frozen\n// Trust & Safety spec (Appendix A §A11 [H6] / [H-17] / [H-18]) — no invented values,\n// no placeholders; the durable design owner is ttt-prod\n// docs/design/nonconsensual-intimate-imagery-and-take-it-down.md. The schemas pin\n// each literal-defaulted field where the spec fixes a single literal value\n// (`policyVersion`, `approvedBy`, `counselApproved`, the security-profile string\n// literals, etc.) so a config write cannot silently drift from the frozen posture.\n//\n// Collection note: these are `_config` singleton docs; wiring collections.ts /\n// path-builders.ts / registry.ts is deferred to the app leg.\n\nimport { z } from 'zod';\n\n// ===========================================================================\n// §A11 [H6] — NciiPolicyConfigV1 + DEFAULT_NCII_POLICY_CONFIG_V1\n// `_serverData/nciiPolicy`\n// ===========================================================================\n\n/** Blocked-hash retention policy — indefinite until an appeal reverses it. */\nexport const NciiBlockedHashRetentionPolicySchema = z.literal('indefiniteUntilReversed');\nexport type NciiBlockedHashRetentionPolicy = z.infer<typeof NciiBlockedHashRetentionPolicySchema>;\n\n/** `_serverData/nciiPolicy` = `NciiPolicyConfigV1` — the DJ-approved launch defaults.\n * Counsel ratifies (`counselApproved`) at the pre-launch gate; uploads stay\n * blocked until then. Any value missing/placeholder → the launch audit FAILS\n * CLOSED. */\nexport const NciiPolicyConfigV1Schema = z.object({\n policyVersion: z.literal('ncii.2026-06-23.v1'),\n requesterPiiRetentionDays: z.number(),\n evidenceRetentionDays: z.number(),\n blockedHashRetentionPolicy: NciiBlockedHashRetentionPolicySchema,\n allowedEvidenceMimeTypes: z.array(z.string().min(1)),\n maxEvidenceFileBytes: z.number(),\n maxEvidenceFilesPerRequest: z.number(),\n maxEvidenceTotalBytesPerRequest: z.number(),\n uploadReservationMinutes: z.number(),\n abandonedUploadCleanupHours: z.number(),\n // [H1/M3] temp-hold values:\n tempHoldInitialHours: z.number(),\n tempHoldPendingValidityExtensionHours: z.number(),\n tempHoldMaxTotalHours: z.number(),\n incompleteInvalidReleaseDelayHours: z.number(),\n // [NCII route rate-limit hardening — 2026-07-01, OPERATIONAL operator defaults, not legal-retention\n // values; counsel may tune]. The public intake route returns 429 + Retry-After and NEVER discards a\n // submission. App-Check is the PRIMARY defense with only a GENEROUS per-IP burst backstop (generous\n // enough not to throttle a real VPN/shared-IP victim — per-IP was rejected for the evidence BYTES\n // path; this is the HTTP route only). (The supplement route + status token were removed with the\n // public post-submission tracking tail — the public flow is submit-only.)\n intakeRateLimitWindowSeconds: z.number(),\n intakeRateLimitMaxPerIp: z.number(),\n // [H-07] dedup window for the deterministic initial-intake idempotency key\n idempotencyWindowHours: z.number(),\n // [M-10] evidence parser-hardening budgets (attacker-controlled bytes):\n maxEvidenceDecodePixels: z.number(),\n maxEvidenceImageDimension: z.number(),\n maxEvidenceVideoFrames: z.number(),\n maxEvidenceVideoDurationSec: z.number(),\n evidenceParserTimeoutSec: z.number(),\n evidenceScanCpuBudgetMs: z.number(),\n evidenceScanMemoryBudgetMb: z.number(),\n rejectArchiveAndPolyglotPayloads: z.boolean(),\n approvedBy: z.literal('operatorLaunchDefault'),\n // counselApproved flips true at the pre-launch counsel gate; uploads stay blocked until then\n counselApproved: z.boolean(),\n}).strict();\nexport type NciiPolicyConfigV1 = z.infer<typeof NciiPolicyConfigV1Schema>;\n\n/** The frozen launch default for `_serverData/nciiPolicy`. */\nexport const DEFAULT_NCII_POLICY_CONFIG_V1: NciiPolicyConfigV1 = {\n policyVersion: 'ncii.2026-06-23.v1',\n requesterPiiRetentionDays: 90,\n evidenceRetentionDays: 60,\n blockedHashRetentionPolicy: 'indefiniteUntilReversed',\n allowedEvidenceMimeTypes: ['image/jpeg', 'image/png', 'image/webp', 'image/gif', 'video/mp4', 'video/webm'],\n // [H-01/R10] 100MB per file (was 500MB): the evidence-scan trigger downloads the whole object into a\n // ~512MiB Function before scanning, so an allowed file must fit in memory. Total = 3×100MB = 300MB.\n // Count stays 3. The storage.rules `nciiEvidence` per-file cap mirrors this 100MB (rules can't read\n // this config).\n maxEvidenceFileBytes: 104857600,\n maxEvidenceFilesPerRequest: 3,\n maxEvidenceTotalBytesPerRequest: 314572800,\n uploadReservationMinutes: 30,\n abandonedUploadCleanupHours: 24,\n tempHoldInitialHours: 72,\n tempHoldPendingValidityExtensionHours: 48,\n tempHoldMaxTotalHours: 336,\n incompleteInvalidReleaseDelayHours: 24,\n // [NCII route rate-limit hardening — 2026-07-01 operator defaults; generous, counsel may tune]\n intakeRateLimitWindowSeconds: 3600, // per source IP (secondary flood guard; App-Check is primary)\n intakeRateLimitMaxPerIp: 20, // generous so a shared/VPN IP with several genuine victims isn't throttled\n idempotencyWindowHours: 72,\n maxEvidenceDecodePixels: 40000000,\n maxEvidenceImageDimension: 12000,\n maxEvidenceVideoFrames: 600,\n maxEvidenceVideoDurationSec: 600,\n evidenceParserTimeoutSec: 60,\n evidenceScanCpuBudgetMs: 30000,\n evidenceScanMemoryBudgetMb: 512,\n rejectArchiveAndPolyglotPayloads: true,\n approvedBy: 'operatorLaunchDefault',\n counselApproved: false,\n};\n\n// ===========================================================================\n// §A11 [H-17] — PrivilegedReviewerSecurityProfileV1 +\n// DEFAULT_PRIVILEGED_REVIEWER_SECURITY_PROFILE_V1\n// `_serverData/privilegedReviewerSecurity`\n//\n// \"fresh reauth\" / \"two-step reauth\" for ANY privileged-reviewer capability means\n// a reauth that satisfies THIS profile — NEVER a bare password re-prompt. Enforced\n// even though one solo operator holds every capability at launch.\n// ===========================================================================\n\n/** The phishing-resistant second factor — password-only, SMS, and TOTP are NEVER\n * sufficient for a privileged capability. */\nexport const PrivilegedReviewerSecondFactorSchema = z.literal('passkeyWebAuthn');\nexport type PrivilegedReviewerSecondFactor = z.infer<typeof PrivilegedReviewerSecondFactorSchema>;\n\n/** The capabilities that require the passkey assertion + an explicit typed\n * confirmation (two-step reauth). */\nexport const PrivilegedTwoStepReauthCapabilitySchema = z.enum([\n 'evidenceReveal',\n 'ncmecCredentialUse',\n 'reverseHashBlock',\n 'legalDisposition',\n 'falsePositiveCorrection',\n 'ncmecManualFallback',\n]);\nexport type PrivilegedTwoStepReauthCapability = z.infer<typeof PrivilegedTwoStepReauthCapabilitySchema>;\n\n/** `_serverData/privilegedReviewerSecurity` = `PrivilegedReviewerSecurityProfileV1` —\n * what \"fresh reauth\" actually means for any privileged-reviewer capability. */\nexport const PrivilegedReviewerSecurityProfileV1Schema = z.object({\n // phishing-resistant; password-only, SMS, and TOTP are NEVER sufficient for a privileged capability\n requiredSecondFactor: PrivilegedReviewerSecondFactorSchema,\n // a capability invocation needs a WebAuthn assertion at least this fresh; older → re-prompt\n privilegedReauthTtlSeconds: z.number(),\n // the privileged session is bound to the enrolled authenticator/device; separate from the ordinary app session\n privilegedSessionDeviceBound: z.boolean(),\n // these require the passkey assertion + an explicit typed confirmation\n twoStepReauthCapabilities: z.array(PrivilegedTwoStepReauthCapabilitySchema),\n // offline one-time break-glass codes, generated at enrollment, stored physically offline\n recoveryCodeCount: z.number(),\n // using one is logged, fires the external critical alarm, and forces enrolling a fresh passkey\n recoveryCodeUse: z.literal('auditedHighSeverity+forcesReenroll+criticalAlarm'),\n // lost-device: revoke ALL privileged sessions → forces re-enrollment before any capability works again\n allowPrivilegedSessionRevocation: z.boolean(),\n // each privileged-capability use writes an audit event (actor, capability, caseId, reauth method, before/after for evidence reads)\n everyInvocationAudited: z.boolean(),\n}).strict();\nexport type PrivilegedReviewerSecurityProfileV1 = z.infer<typeof PrivilegedReviewerSecurityProfileV1Schema>;\n\n/** The frozen launch default for `_serverData/privilegedReviewerSecurity`. */\nexport const DEFAULT_PRIVILEGED_REVIEWER_SECURITY_PROFILE_V1: PrivilegedReviewerSecurityProfileV1 = {\n requiredSecondFactor: 'passkeyWebAuthn',\n privilegedReauthTtlSeconds: 300,\n privilegedSessionDeviceBound: true,\n twoStepReauthCapabilities: [\n 'evidenceReveal',\n 'ncmecCredentialUse',\n 'reverseHashBlock',\n 'legalDisposition',\n 'falsePositiveCorrection',\n 'ncmecManualFallback',\n ],\n recoveryCodeCount: 10,\n recoveryCodeUse: 'auditedHighSeverity+forcesReenroll+criticalAlarm',\n allowPrivilegedSessionRevocation: true,\n everyInvocationAudited: true,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/doc-schemas/ncii/config.ts"],"names":[],"mappings":"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","sourcesContent":["// Trust & Safety — NCII config singletons (Appendix A §A11 [H6] / [H-17] / [H-18]).\n//\n// Two Admin-SDK-only `_serverData` singleton documents, wired into COLLECTIONS,\n// PATH_BUILDERS, and the doc-schema registry:\n// - `_serverData/nciiPolicy` → NciiPolicyConfigV1\n// - `_serverData/privilegedReviewerSecurity` → PrivilegedReviewerSecurityProfileV1\n//\n// These are VERSIONED operator launch defaults (`approvedBy: 'operatorLaunchDefault'`);\n// a reader falls back to the frozen DEFAULT when the stored doc is absent. Any change\n// increments the policy version and triggers a retention/configuration review.\n//\n// Every value in the DEFAULT consts below is transcribed verbatim from the frozen\n// Trust & Safety spec (Appendix A §A11 [H6] / [H-17] / [H-18]) — no invented values,\n// no placeholders; the durable design owner is ttt-prod\n// docs/design/nonconsensual-intimate-imagery-and-take-it-down.md. The schemas pin\n// each literal-defaulted field where the spec fixes a single literal value\n// (`policyVersion`, `approvedBy`, the security-profile string literals, etc.) so a\n// config write cannot silently drift from the frozen posture.\n\nimport { z } from 'zod';\n\n// ===========================================================================\n// §A11 [H6] — NciiPolicyConfigV1 + DEFAULT_NCII_POLICY_CONFIG_V1\n// `_serverData/nciiPolicy`\n// ===========================================================================\n\n/** Blocked-hash retention policy — indefinite until an appeal reverses it. */\nexport const NciiBlockedHashRetentionPolicySchema = z.literal('indefiniteUntilReversed');\nexport type NciiBlockedHashRetentionPolicy = z.infer<typeof NciiBlockedHashRetentionPolicySchema>;\n\n/** `_serverData/nciiPolicy` = `NciiPolicyConfigV1` — the operator launch defaults. */\nexport const NciiPolicyConfigV1Schema = z.object({\n policyVersion: z.literal('ncii.2026-06-23.v1'),\n requesterPiiRetentionDays: z.number(),\n evidenceRetentionDays: z.number(),\n blockedHashRetentionPolicy: NciiBlockedHashRetentionPolicySchema,\n allowedEvidenceMimeTypes: z.array(z.string().min(1)),\n maxEvidenceFileBytes: z.number(),\n maxEvidenceFilesPerRequest: z.number(),\n maxEvidenceTotalBytesPerRequest: z.number(),\n uploadReservationMinutes: z.number(),\n abandonedUploadCleanupHours: z.number(),\n // [H1/M3] temp-hold values:\n tempHoldInitialHours: z.number(),\n tempHoldPendingValidityExtensionHours: z.number(),\n tempHoldMaxTotalHours: z.number(),\n incompleteInvalidReleaseDelayHours: z.number(),\n // [NCII route rate-limit hardening — 2026-07-01, OPERATIONAL operator defaults, not legal-retention\n // values; counsel may tune]. The public intake route returns 429 + Retry-After and NEVER discards a\n // submission. App-Check is the PRIMARY defense with only a GENEROUS per-IP burst backstop (generous\n // enough not to throttle a real VPN/shared-IP victim — per-IP was rejected for the evidence BYTES\n // path; this is the HTTP route only). (The supplement route + status token were removed with the\n // public post-submission tracking tail — the public flow is submit-only.)\n intakeRateLimitWindowSeconds: z.number(),\n intakeRateLimitMaxPerIp: z.number(),\n // [H-07] dedup window for the deterministic initial-intake idempotency key\n idempotencyWindowHours: z.number(),\n // [M-10] evidence parser-hardening budgets (attacker-controlled bytes):\n maxEvidenceDecodePixels: z.number(),\n maxEvidenceImageDimension: z.number(),\n maxEvidenceVideoFrames: z.number(),\n maxEvidenceVideoDurationSec: z.number(),\n evidenceParserTimeoutSec: z.number(),\n evidenceScanCpuBudgetMs: z.number(),\n evidenceScanMemoryBudgetMb: z.number(),\n rejectArchiveAndPolyglotPayloads: z.boolean(),\n approvedBy: z.literal('operatorLaunchDefault'),\n}).strict();\nexport type NciiPolicyConfigV1 = z.infer<typeof NciiPolicyConfigV1Schema>;\n\n/** The frozen launch default for `_serverData/nciiPolicy`. */\nexport const DEFAULT_NCII_POLICY_CONFIG_V1: NciiPolicyConfigV1 = {\n policyVersion: 'ncii.2026-06-23.v1',\n requesterPiiRetentionDays: 90,\n evidenceRetentionDays: 60,\n blockedHashRetentionPolicy: 'indefiniteUntilReversed',\n allowedEvidenceMimeTypes: ['image/jpeg', 'image/png', 'image/webp', 'image/gif', 'video/mp4', 'video/webm'],\n // [H-01/R10] 100MB per file (was 500MB): the evidence-scan trigger downloads the whole object into a\n // ~512MiB Function before scanning, so an allowed file must fit in memory. Total = 3×100MB = 300MB.\n // Count stays 3. The storage.rules `nciiEvidence` per-file cap mirrors this 100MB (rules can't read\n // this config).\n maxEvidenceFileBytes: 104857600,\n maxEvidenceFilesPerRequest: 3,\n maxEvidenceTotalBytesPerRequest: 314572800,\n uploadReservationMinutes: 30,\n abandonedUploadCleanupHours: 24,\n tempHoldInitialHours: 72,\n tempHoldPendingValidityExtensionHours: 48,\n tempHoldMaxTotalHours: 336,\n incompleteInvalidReleaseDelayHours: 24,\n // [NCII route rate-limit hardening — 2026-07-01 operator defaults; generous, counsel may tune]\n intakeRateLimitWindowSeconds: 3600, // per source IP (secondary flood guard; App-Check is primary)\n intakeRateLimitMaxPerIp: 20, // generous so a shared/VPN IP with several genuine victims isn't throttled\n idempotencyWindowHours: 72,\n maxEvidenceDecodePixels: 40000000,\n maxEvidenceImageDimension: 12000,\n maxEvidenceVideoFrames: 600,\n maxEvidenceVideoDurationSec: 600,\n evidenceParserTimeoutSec: 60,\n evidenceScanCpuBudgetMs: 30000,\n evidenceScanMemoryBudgetMb: 512,\n rejectArchiveAndPolyglotPayloads: true,\n approvedBy: 'operatorLaunchDefault',\n};\n\n// ===========================================================================\n// §A11 [H-17] — PrivilegedReviewerSecurityProfileV1 +\n// DEFAULT_PRIVILEGED_REVIEWER_SECURITY_PROFILE_V1\n// `_serverData/privilegedReviewerSecurity`\n//\n// \"fresh reauth\" / \"two-step reauth\" for ANY privileged-reviewer capability means\n// a reauth that satisfies THIS profile — NEVER a bare password re-prompt. Enforced\n// even though one solo operator holds every capability at launch.\n// ===========================================================================\n\n/** The phishing-resistant second factor — password-only, SMS, and TOTP are NEVER\n * sufficient for a privileged capability. */\nexport const PrivilegedReviewerSecondFactorSchema = z.literal('passkeyWebAuthn');\nexport type PrivilegedReviewerSecondFactor = z.infer<typeof PrivilegedReviewerSecondFactorSchema>;\n\n/** The capabilities that require the passkey assertion + an explicit typed\n * confirmation (two-step reauth). */\nexport const PrivilegedTwoStepReauthCapabilitySchema = z.enum([\n 'evidenceReveal',\n 'ncmecCredentialUse',\n 'reverseHashBlock',\n 'legalDisposition',\n 'falsePositiveCorrection',\n 'ncmecManualFallback',\n]);\nexport type PrivilegedTwoStepReauthCapability = z.infer<typeof PrivilegedTwoStepReauthCapabilitySchema>;\n\n/** `_serverData/privilegedReviewerSecurity` = `PrivilegedReviewerSecurityProfileV1` —\n * what \"fresh reauth\" actually means for any privileged-reviewer capability. */\nexport const PrivilegedReviewerSecurityProfileV1Schema = z.object({\n // phishing-resistant; password-only, SMS, and TOTP are NEVER sufficient for a privileged capability\n requiredSecondFactor: PrivilegedReviewerSecondFactorSchema,\n // a capability invocation needs a WebAuthn assertion at least this fresh; older → re-prompt\n privilegedReauthTtlSeconds: z.number(),\n // the privileged session is bound to the enrolled authenticator/device; separate from the ordinary app session\n privilegedSessionDeviceBound: z.boolean(),\n // these require the passkey assertion + an explicit typed confirmation\n twoStepReauthCapabilities: z.array(PrivilegedTwoStepReauthCapabilitySchema),\n // offline one-time break-glass codes, generated at enrollment, stored physically offline\n recoveryCodeCount: z.number(),\n // using one is logged, fires the external critical alarm, and forces enrolling a fresh passkey\n recoveryCodeUse: z.literal('auditedHighSeverity+forcesReenroll+criticalAlarm'),\n // lost-device: revoke ALL privileged sessions → forces re-enrollment before any capability works again\n allowPrivilegedSessionRevocation: z.boolean(),\n // each privileged-capability use writes an audit event (actor, capability, caseId, reauth method, before/after for evidence reads)\n everyInvocationAudited: z.boolean(),\n}).strict();\nexport type PrivilegedReviewerSecurityProfileV1 = z.infer<typeof PrivilegedReviewerSecurityProfileV1Schema>;\n\n/** The frozen launch default for `_serverData/privilegedReviewerSecurity`. */\nexport const DEFAULT_PRIVILEGED_REVIEWER_SECURITY_PROFILE_V1: PrivilegedReviewerSecurityProfileV1 = {\n requiredSecondFactor: 'passkeyWebAuthn',\n privilegedReauthTtlSeconds: 300,\n privilegedSessionDeviceBound: true,\n twoStepReauthCapabilities: [\n 'evidenceReveal',\n 'ncmecCredentialUse',\n 'reverseHashBlock',\n 'legalDisposition',\n 'falsePositiveCorrection',\n 'ncmecManualFallback',\n ],\n recoveryCodeCount: 10,\n recoveryCodeUse: 'auditedHighSeverity+forcesReenroll+criticalAlarm',\n allowPrivilegedSessionRevocation: true,\n everyInvocationAudited: true,\n};\n"]}
|
|
@@ -42,18 +42,63 @@ export declare const ShortLinkSchema: z.ZodObject<{
|
|
|
42
42
|
clicks: z.ZodNumber;
|
|
43
43
|
}, z.core.$strip>;
|
|
44
44
|
export type ShortLink = z.infer<typeof ShortLinkSchema>;
|
|
45
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Which post-commit Auth effect failed and queued the uid:
|
|
47
|
+
* - `accountStatus` — the status claim / `disabled` flag / token revocation after a status change;
|
|
48
|
+
* - `publicDocumentsAcceptedClaim` — the `docsAccepted` claim after a public-document acceptance.
|
|
49
|
+
* An entry without `authEffect` predates the field and is an `accountStatus` entry.
|
|
50
|
+
*/
|
|
51
|
+
export declare const STATUS_RECONCILE_QUEUE_AUTH_EFFECTS: readonly ["accountStatus", "publicDocumentsAcceptedClaim"];
|
|
52
|
+
export declare const StatusReconcileQueueAuthEffectSchema: z.ZodEnum<{
|
|
53
|
+
accountStatus: "accountStatus";
|
|
54
|
+
publicDocumentsAcceptedClaim: "publicDocumentsAcceptedClaim";
|
|
55
|
+
}>;
|
|
56
|
+
export type StatusReconcileQueueAuthEffect = z.infer<typeof StatusReconcileQueueAuthEffectSchema>;
|
|
57
|
+
/** A failed status effect: the drain drives the account toward `targetStatus`. */
|
|
58
|
+
export declare const StatusReconcileQueueAccountStatusEntrySchema: z.ZodObject<{
|
|
59
|
+
authEffect: z.ZodOptional<z.ZodLiteral<"accountStatus">>;
|
|
60
|
+
targetStatus: z.ZodEnum<{
|
|
61
|
+
banned: "banned";
|
|
62
|
+
active: "active";
|
|
63
|
+
suspended: "suspended";
|
|
64
|
+
}>;
|
|
65
|
+
uid: z.ZodString;
|
|
66
|
+
enqueuedAt: z.ZodNumber;
|
|
67
|
+
lastAttemptAt: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
attemptCount: z.ZodNumber;
|
|
69
|
+
reason: z.ZodLiteral<"postCommitAuthEffectFailed">;
|
|
70
|
+
}, z.core.$strip>;
|
|
71
|
+
export type StatusReconcileQueueAccountStatusEntry = z.infer<typeof StatusReconcileQueueAccountStatusEntrySchema>;
|
|
72
|
+
/** A failed `docsAccepted` claim write. Strict: it carries no status, so no `targetStatus`. */
|
|
73
|
+
export declare const StatusReconcileQueuePublicDocumentsAcceptedClaimEntrySchema: z.ZodObject<{
|
|
74
|
+
authEffect: z.ZodLiteral<"publicDocumentsAcceptedClaim">;
|
|
46
75
|
uid: z.ZodString;
|
|
47
76
|
enqueuedAt: z.ZodNumber;
|
|
48
77
|
lastAttemptAt: z.ZodOptional<z.ZodNumber>;
|
|
49
78
|
attemptCount: z.ZodNumber;
|
|
79
|
+
reason: z.ZodLiteral<"postCommitAuthEffectFailed">;
|
|
80
|
+
}, z.core.$strict>;
|
|
81
|
+
export type StatusReconcileQueuePublicDocumentsAcceptedClaimEntry = z.infer<typeof StatusReconcileQueuePublicDocumentsAcceptedClaimEntrySchema>;
|
|
82
|
+
export declare const StatusReconcileQueueEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
83
|
+
authEffect: z.ZodOptional<z.ZodLiteral<"accountStatus">>;
|
|
50
84
|
targetStatus: z.ZodEnum<{
|
|
51
85
|
banned: "banned";
|
|
52
86
|
active: "active";
|
|
53
87
|
suspended: "suspended";
|
|
54
88
|
}>;
|
|
89
|
+
uid: z.ZodString;
|
|
90
|
+
enqueuedAt: z.ZodNumber;
|
|
91
|
+
lastAttemptAt: z.ZodOptional<z.ZodNumber>;
|
|
92
|
+
attemptCount: z.ZodNumber;
|
|
55
93
|
reason: z.ZodLiteral<"postCommitAuthEffectFailed">;
|
|
56
|
-
}, z.core.$strip
|
|
94
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
95
|
+
authEffect: z.ZodLiteral<"publicDocumentsAcceptedClaim">;
|
|
96
|
+
uid: z.ZodString;
|
|
97
|
+
enqueuedAt: z.ZodNumber;
|
|
98
|
+
lastAttemptAt: z.ZodOptional<z.ZodNumber>;
|
|
99
|
+
attemptCount: z.ZodNumber;
|
|
100
|
+
reason: z.ZodLiteral<"postCommitAuthEffectFailed">;
|
|
101
|
+
}, z.core.$strict>], "authEffect">;
|
|
57
102
|
export type StatusReconcileQueueEntry = z.infer<typeof StatusReconcileQueueEntrySchema>;
|
|
58
103
|
export declare const FeedbackAliasSchema: z.ZodObject<{
|
|
59
104
|
canonicalId: z.ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operational.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/operational.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,yBAAyB;;;iBAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAK5E,eAAO,MAAM,uBAAuB;;;;iBASlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE,eAAO,MAAM,0BAA0B;;;;;;;;;;;iBAWrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAO9E,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;iBAa1B,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"operational.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/operational.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,yBAAyB;;;iBAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAK5E,eAAO,MAAM,uBAAuB;;;;iBASlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE,eAAO,MAAM,0BAA0B;;;;;;;;;;;iBAWrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAO9E,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;iBAa1B,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AASxD;;;;;GAKG;AACH,eAAO,MAAM,mCAAmC,4DAA6D,CAAC;AAC9G,eAAO,MAAM,oCAAoC;;;EAA8C,CAAC;AAChG,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAUlG,kFAAkF;AAClF,eAAO,MAAM,4CAA4C;;;;;;;;;;;;iBAIvD,CAAC;AACH,MAAM,MAAM,sCAAsC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4CAA4C,CAAC,CAAC;AAElH,+FAA+F;AAC/F,eAAO,MAAM,2DAA2D;;;;;;;kBAK7D,CAAC;AACZ,MAAM,MAAM,qDAAqD,GAAG,CAAC,CAAC,KAAK,CACzE,OAAO,2DAA2D,CACnE,CAAC;AAEF,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;kCAG1C,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAIxF,eAAO,MAAM,mBAAmB;;;iBAG9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAKhE,eAAO,MAAM,oBAAoB;;;;;;;iBAK/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|
|
@@ -54,19 +54,44 @@ export const ShortLinkSchema = z.object({
|
|
|
54
54
|
createdBy: z.string(),
|
|
55
55
|
clicks: z.number(),
|
|
56
56
|
});
|
|
57
|
-
// statusReconcileQueue/{uid} — backend-only retry queue for post-commit
|
|
58
|
-
// Written when
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
// Timestamps are epoch-millis numbers (this repo never uses Firestore
|
|
62
|
-
|
|
57
|
+
// statusReconcileQueue/{uid} — backend-only retry queue for post-commit Auth-effect reconciliation.
|
|
58
|
+
// Written when a change committed to Firestore but its follow-on Auth effect failed; the drain
|
|
59
|
+
// re-converges every Auth-side mirror of the uid from its canonical docs and deletes the entry on
|
|
60
|
+
// success. Keyed by the affected uid (doc id == uid; one entry per uid, whichever effect queued
|
|
61
|
+
// it); Admin-SDK-only. Timestamps are epoch-millis numbers (this repo never uses Firestore
|
|
62
|
+
// Timestamps).
|
|
63
|
+
/**
|
|
64
|
+
* Which post-commit Auth effect failed and queued the uid:
|
|
65
|
+
* - `accountStatus` — the status claim / `disabled` flag / token revocation after a status change;
|
|
66
|
+
* - `publicDocumentsAcceptedClaim` — the `docsAccepted` claim after a public-document acceptance.
|
|
67
|
+
* An entry without `authEffect` predates the field and is an `accountStatus` entry.
|
|
68
|
+
*/
|
|
69
|
+
export const STATUS_RECONCILE_QUEUE_AUTH_EFFECTS = ['accountStatus', 'publicDocumentsAcceptedClaim'];
|
|
70
|
+
export const StatusReconcileQueueAuthEffectSchema = z.enum(STATUS_RECONCILE_QUEUE_AUTH_EFFECTS);
|
|
71
|
+
const statusReconcileQueueEntryBase = {
|
|
63
72
|
uid: z.string(),
|
|
64
73
|
enqueuedAt: z.number(),
|
|
65
74
|
lastAttemptAt: z.number().optional(),
|
|
66
75
|
attemptCount: z.number(),
|
|
67
|
-
targetStatus: UserAccountStatusSchema,
|
|
68
76
|
reason: z.literal('postCommitAuthEffectFailed'),
|
|
77
|
+
};
|
|
78
|
+
/** A failed status effect: the drain drives the account toward `targetStatus`. */
|
|
79
|
+
export const StatusReconcileQueueAccountStatusEntrySchema = z.object({
|
|
80
|
+
...statusReconcileQueueEntryBase,
|
|
81
|
+
authEffect: z.literal('accountStatus').optional(),
|
|
82
|
+
targetStatus: UserAccountStatusSchema,
|
|
69
83
|
});
|
|
84
|
+
/** A failed `docsAccepted` claim write. Strict: it carries no status, so no `targetStatus`. */
|
|
85
|
+
export const StatusReconcileQueuePublicDocumentsAcceptedClaimEntrySchema = z
|
|
86
|
+
.object({
|
|
87
|
+
...statusReconcileQueueEntryBase,
|
|
88
|
+
authEffect: z.literal('publicDocumentsAcceptedClaim'),
|
|
89
|
+
})
|
|
90
|
+
.strict();
|
|
91
|
+
export const StatusReconcileQueueEntrySchema = z.discriminatedUnion('authEffect', [
|
|
92
|
+
StatusReconcileQueueAccountStatusEntrySchema,
|
|
93
|
+
StatusReconcileQueuePublicDocumentsAcceptedClaimEntrySchema,
|
|
94
|
+
]);
|
|
70
95
|
// feedbackAliases/{aliasId} — Console-managed map collapsing a synonym suggestion onto a canonical
|
|
71
96
|
// one; read by submitFeedback, no callable writes it. (firestore.rules §3F / submitFeedback.ts)
|
|
72
97
|
export const FeedbackAliasSchema = z.object({
|