@ttt-productions/ttt-core 0.78.2 → 0.78.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/constants/business-admin.d.ts +3 -0
  2. package/dist/constants/business-admin.d.ts.map +1 -1
  3. package/dist/constants/business-admin.js +3 -0
  4. package/dist/constants/business-admin.js.map +1 -1
  5. package/dist/constants/business-content.d.ts +40 -2
  6. package/dist/constants/business-content.d.ts.map +1 -1
  7. package/dist/constants/business-content.js +52 -9
  8. package/dist/constants/business-content.js.map +1 -1
  9. package/dist/doc-schemas/chat-sync.d.ts +1 -1
  10. package/dist/doc-schemas/media-activation-jobs.d.ts +1 -1
  11. package/dist/doc-schemas/media-assets.d.ts +7 -7
  12. package/dist/doc-schemas/moderation.d.ts +2 -2
  13. package/dist/doc-schemas/ncii/requests.d.ts +1 -1
  14. package/dist/doc-schemas/notifications.d.ts +9 -9
  15. package/dist/doc-schemas/notifications.d.ts.map +1 -1
  16. package/dist/doc-schemas/notifications.js +14 -38
  17. package/dist/doc-schemas/notifications.js.map +1 -1
  18. package/dist/doc-schemas/registry.d.ts +13 -13
  19. package/dist/doc-schemas/registry.d.ts.map +1 -1
  20. package/dist/doc-schemas/registry.js +3 -0
  21. package/dist/doc-schemas/registry.js.map +1 -1
  22. package/dist/doc-schemas/safety/case.d.ts +20 -0
  23. package/dist/doc-schemas/safety/case.d.ts.map +1 -1
  24. package/dist/doc-schemas/safety/case.js +13 -1
  25. package/dist/doc-schemas/safety/case.js.map +1 -1
  26. package/dist/doc-schemas/safety/evidence.d.ts +12 -4
  27. package/dist/doc-schemas/safety/evidence.d.ts.map +1 -1
  28. package/dist/doc-schemas/safety/evidence.js +18 -4
  29. package/dist/doc-schemas/safety/evidence.js.map +1 -1
  30. package/dist/doc-schemas/safety/foundation.d.ts +2 -2
  31. package/dist/doc-schemas/safety/holds.d.ts +1 -1
  32. package/dist/doc-schemas/social.d.ts +3 -3
  33. package/dist/media/atoms.d.ts +2 -2
  34. package/dist/media/target-info.d.ts +1 -3
  35. package/dist/media/target-info.d.ts.map +1 -1
  36. package/dist/media/target-info.js +14 -2
  37. package/dist/media/target-info.js.map +1 -1
  38. package/dist/paths/collections.d.ts +1 -0
  39. package/dist/paths/collections.d.ts.map +1 -1
  40. package/dist/paths/collections.js +2 -0
  41. package/dist/paths/collections.js.map +1 -1
  42. package/dist/paths/path-builders.d.ts +14 -0
  43. package/dist/paths/path-builders.d.ts.map +1 -1
  44. package/dist/paths/path-builders.js +29 -0
  45. package/dist/paths/path-builders.js.map +1 -1
  46. package/dist/safety/active-safety-case-alert.d.ts +33 -0
  47. package/dist/safety/active-safety-case-alert.d.ts.map +1 -0
  48. package/dist/safety/active-safety-case-alert.js +49 -0
  49. package/dist/safety/active-safety-case-alert.js.map +1 -0
  50. package/dist/safety/index.d.ts +4 -0
  51. package/dist/safety/index.d.ts.map +1 -0
  52. package/dist/safety/index.js +7 -0
  53. package/dist/safety/index.js.map +1 -0
  54. package/dist/safety/ncii-intake-derivations.d.ts +63 -0
  55. package/dist/safety/ncii-intake-derivations.d.ts.map +1 -0
  56. package/dist/safety/ncii-intake-derivations.js +227 -0
  57. package/dist/safety/ncii-intake-derivations.js.map +1 -0
  58. package/dist/safety/resource-keys.d.ts +60 -0
  59. package/dist/safety/resource-keys.d.ts.map +1 -0
  60. package/dist/safety/resource-keys.js +122 -0
  61. package/dist/safety/resource-keys.js.map +1 -0
  62. package/dist/schemas/admin-dispatch-actions.d.ts +4 -0
  63. package/dist/schemas/admin-dispatch-actions.d.ts.map +1 -1
  64. package/dist/schemas/admin-dispatch-actions.js +5 -0
  65. package/dist/schemas/admin-dispatch-actions.js.map +1 -1
  66. package/dist/schemas/admin.d.ts +78 -0
  67. package/dist/schemas/admin.d.ts.map +1 -1
  68. package/dist/schemas/admin.js +69 -1
  69. package/dist/schemas/admin.js.map +1 -1
  70. package/dist/schemas/chat.d.ts +51 -0
  71. package/dist/schemas/chat.d.ts.map +1 -1
  72. package/dist/schemas/chat.js +44 -1
  73. package/dist/schemas/chat.js.map +1 -1
  74. package/dist/schemas/safety.d.ts +67 -0
  75. package/dist/schemas/safety.d.ts.map +1 -1
  76. package/dist/schemas/safety.js +63 -0
  77. package/dist/schemas/safety.js.map +1 -1
  78. package/dist/schemas/social.d.ts +2 -2
  79. package/dist/schemas/utility.d.ts +4 -0
  80. package/dist/schemas/utility.d.ts.map +1 -1
  81. package/dist/schemas/utility.js +5 -0
  82. package/dist/schemas/utility.js.map +1 -1
  83. package/dist/upload-variables/square-streetz-post-variables.d.ts +1 -1
  84. package/package.json +10 -6
@@ -0,0 +1,63 @@
1
+ import { resourceKeyHash } from './resource-keys.js';
2
+ import type { TakeItDownFieldCode, TakeItDownRequesterRole, TargetLocatorV1, TargetLocatorSummaryV1 } from '../doc-schemas/index.js';
3
+ /**
4
+ * sha256-hex chokepoint. Aliased to `resourceKeyHash` (the single canonical hashing
5
+ * helper in `./resource-keys`) so the whole `./safety` surface has ONE sha256
6
+ * implementation, never two. Named `sha256Hex` here because these intake derivations
7
+ * hash arbitrary keyspace strings, not resource keys.
8
+ */
9
+ export declare const sha256Hex: typeof resourceKeyHash;
10
+ /** Deterministic `nciiTemporaryHolds/{holdId}` doc id for a request. ONE definition shared
11
+ * by intake (which writes the row) and the removal saga (which reads its `target` locator as
12
+ * the fallback when a public-form request has no case-linked allegation). */
13
+ export declare function tempHoldId(requestId: string): string;
14
+ /**
15
+ * Canonical, collision-resistant key for a request target. For a resolvable
16
+ * TTT-hosted locator the key is the locator discriminant + its identity fields;
17
+ * for an external/unresolvable locator (a bare URL or free text) it is the
18
+ * `url`/`additionalText` payload. The SAME logical target ALWAYS normalizes to the
19
+ * SAME key so two submissions about the same content with the same idempotencyKey
20
+ * resolve to ONE request doc, and two DIFFERENT targets never collide.
21
+ *
22
+ * No JSON — a flat unit-separator-joined string (the separator is illegal in any
23
+ * id/url field) is stable by construction (no key-ordering ambiguity).
24
+ */
25
+ export declare function normalizedTargetKey(locator: TargetLocatorV1): string;
26
+ /** Best-effort URL normalization for the external-locator key. A non-parseable
27
+ * string is lowercased + trimmed (still deterministic). NEVER throws. */
28
+ export declare function normalizeExternalUrl(raw: string): string;
29
+ /**
30
+ * [H-07] The deterministic intake requestId:
31
+ * sha256('takeItDownRequest:v1:' + idempotencyKey + ':' + normalizedTargetKey).
32
+ * A retry with the SAME client idempotencyKey + the SAME target re-derives the SAME
33
+ * id, so the create-if-absent transaction is a no-op and re-returns the same receipt
34
+ * (never double-arms a clock / double-commits a hold).
35
+ */
36
+ export declare function deterministicRequestId(idempotencyKey: string, targetKey: string): string;
37
+ /**
38
+ * The opaque public `requestReference` printed on the one-time receipt and stored on the
39
+ * public-status projection. Since the status token was removed, this is a deterministic
40
+ * derivation of the internal `requestId` — a separate sha256 so the raw `requestId` is
41
+ * never recoverable from the reference (which appears on the receipt / projection).
42
+ * 32 hex chars is ample entropy for an opaque, non-enumerable capability.
43
+ */
44
+ export declare function deriveRequestReference(requestId: string): string;
45
+ /**
46
+ * Deterministic hash of the cumulative request state as of a submission — recorded
47
+ * on `TakeItDownSubmissionV1.cumulativeRequestSnapshotHash`. Built from the SORTED
48
+ * supplied field codes + the normalized target key + the requester role so the same
49
+ * cumulative state always fingerprints identically (append-order independent).
50
+ */
51
+ export declare function cumulativeSnapshotHash(args: {
52
+ requesterRole: TakeItDownRequesterRole;
53
+ targetKey: string;
54
+ suppliedFieldCodes: readonly TakeItDownFieldCode[];
55
+ }): string;
56
+ /** A short, non-sensitive surface label per locator kind (no ids, no narrative). */
57
+ export declare function surfaceLabelFor(locator: TargetLocatorV1): string;
58
+ /** Build the privacy-safe `TargetLocatorSummaryV1` (kind + surface label +
59
+ * whether a TTT-hosted target was server-resolved). NEVER the narrative or ids. */
60
+ export declare function targetLocatorSummary(locator: TargetLocatorV1, hasResolvedTarget: boolean): TargetLocatorSummaryV1;
61
+ /** True when the locator points at a TTT-hosted surface (server-resolvable). */
62
+ export declare function isTttHostedLocator(locator: TargetLocatorV1): boolean;
63
+ //# sourceMappingURL=ncii-intake-derivations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ncii-intake-derivations.d.ts","sourceRoot":"","sources":["../../src/safety/ncii-intake-derivations.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EACvB,eAAe,EACf,sBAAsB,EACvB,MAAM,yBAAyB,CAAC;AAEjC;;;;;GAKG;AACH,eAAO,MAAM,SAAS,wBAAkB,CAAC;AAczC;;8EAE8E;AAC9E,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CA4CpE;AAED;0EAC0E;AAC1E,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUxD;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAExF;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEhE;AAMD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,aAAa,EAAE,uBAAuB,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACpD,GAAG,MAAM,CAKT;AAMD,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAyChE;AAED;oFACoF;AACpF,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,eAAe,EACxB,iBAAiB,EAAE,OAAO,GACzB,sBAAsB,CAMxB;AAmBD,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAEpE"}
@@ -0,0 +1,227 @@
1
+ // Shared NCII / TAKE IT DOWN intake derivations (Trust & Safety IMPLEMENTATION_PLAN
2
+ // Phase NCII-2/3/4, Appendix A §A11). Pure, deterministic id/key/summary derivations
3
+ // used by BOTH the public Next.js intake route and the Cloud Functions deadline/scan
4
+ // workers. These used to be hand-mirrored in two app TS projects (the Cloud Functions
5
+ // graph AND the App Hosting route graph, which cannot cross-import). This is now the ONE
6
+ // canonical declaration (Rule 36 / Cross-Boundary Type Invariant): both module graphs
7
+ // import these derivations from ttt-core so the deterministic id/key contracts can never
8
+ // drift between the two runtimes.
9
+ //
10
+ // These are LOAD-BEARING KEYSPACE CONTRACTS. A formula (or version-tag) change re-keys
11
+ // EVERY existing intake request doc / receipt / snapshot — treat any such change as a
12
+ // breaking migration of the intake keyspace, never a routine edit. The per-function
13
+ // version-bump warnings below are not decorative.
14
+ //
15
+ // node:crypto sha256 keeps this pure + server-safe: this module lives behind the
16
+ // `./safety` entry (never on the main barrel), so the frontend bundle never loads it.
17
+ // The completeness predicate + intake-facts shape are NOT here — they are canonical on
18
+ // `./doc-schemas` (beside `computeCompleteness`); import those from there.
19
+ import { resourceKeyHash } from './resource-keys.js';
20
+ /**
21
+ * sha256-hex chokepoint. Aliased to `resourceKeyHash` (the single canonical hashing
22
+ * helper in `./resource-keys`) so the whole `./safety` surface has ONE sha256
23
+ * implementation, never two. Named `sha256Hex` here because these intake derivations
24
+ * hash arbitrary keyspace strings, not resource keys.
25
+ */
26
+ export const sha256Hex = resourceKeyHash;
27
+ /** Unit separator — illegal in any id/url/field we join, so a flat separator-joined
28
+ * string is stable by construction (no key-ordering ambiguity, no JSON). */
29
+ const SEP = '\x1f';
30
+ // ===========================================================================
31
+ // Deterministic ids ([H-07] idempotent intake)
32
+ // ===========================================================================
33
+ /** Version tag for the deterministic intake requestId. A bump re-keys EVERY
34
+ * request doc id — treat as a breaking migration of the intake keyspace. */
35
+ const REQUEST_ID_VERSION = 'takeItDownRequest:v1';
36
+ /** Deterministic `nciiTemporaryHolds/{holdId}` doc id for a request. ONE definition shared
37
+ * by intake (which writes the row) and the removal saga (which reads its `target` locator as
38
+ * the fallback when a public-form request has no case-linked allegation). */
39
+ export function tempHoldId(requestId) {
40
+ return sha256Hex(`nciiTemporaryHold:v1:${requestId}`);
41
+ }
42
+ /**
43
+ * Canonical, collision-resistant key for a request target. For a resolvable
44
+ * TTT-hosted locator the key is the locator discriminant + its identity fields;
45
+ * for an external/unresolvable locator (a bare URL or free text) it is the
46
+ * `url`/`additionalText` payload. The SAME logical target ALWAYS normalizes to the
47
+ * SAME key so two submissions about the same content with the same idempotencyKey
48
+ * resolve to ONE request doc, and two DIFFERENT targets never collide.
49
+ *
50
+ * No JSON — a flat unit-separator-joined string (the separator is illegal in any
51
+ * id/url field) is stable by construction (no key-ordering ambiguity).
52
+ */
53
+ export function normalizedTargetKey(locator) {
54
+ const k = locator.kind;
55
+ switch (locator.kind) {
56
+ case 'mediaAsset':
57
+ return [k, locator.mediaAssetId].join(SEP);
58
+ case 'hallItem':
59
+ return [k, locator.hallItemId, locator.subItemId ?? ''].join(SEP);
60
+ case 'squarePost':
61
+ return [k, locator.postId].join(SEP);
62
+ case 'profileImage':
63
+ return [k, locator.profileUid].join(SEP);
64
+ case 'username':
65
+ return [k, locator.profileUid].join(SEP);
66
+ case 'craftSkill':
67
+ return [k, locator.profileUid, locator.craftSkillId].join(SEP);
68
+ case 'commissionListing':
69
+ return [k, locator.commissionListingId].join(SEP);
70
+ case 'audition':
71
+ return [k, locator.auditionId].join(SEP);
72
+ case 'auditionEntry':
73
+ return [k, locator.auditionId, locator.auditionEntryId].join(SEP);
74
+ case 'guildInviteMessage':
75
+ return [k, locator.channelId, locator.messageId].join(SEP);
76
+ case 'chatAttachment':
77
+ return [k, locator.channelId, locator.messageId, locator.attachmentId].join(SEP);
78
+ case 'guildChatMessage':
79
+ return [k, locator.channelId, locator.messageId].join(SEP);
80
+ case 'adminWorkMessage':
81
+ return [k, locator.adminDispatchId, locator.messageId].join(SEP);
82
+ case 'commissionProposal':
83
+ return [k, locator.commissionListingId, locator.commissionProposalId].join(SEP);
84
+ case 'workProject':
85
+ return [k, locator.workProjectId].join(SEP);
86
+ case 'workAsset':
87
+ return [k, locator.workProjectId, locator.workAssetId].join(SEP);
88
+ case 'workRealm':
89
+ return [k, locator.workRealmId].join(SEP);
90
+ case 'url':
91
+ // Normalize the URL (trim + lowercase scheme/host) so trivially-different
92
+ // spellings of the same external link collapse to one request.
93
+ return [k, normalizeExternalUrl(locator.url)].join(SEP);
94
+ case 'additionalText':
95
+ return [k, locator.textRef].join(SEP);
96
+ }
97
+ }
98
+ /** Best-effort URL normalization for the external-locator key. A non-parseable
99
+ * string is lowercased + trimmed (still deterministic). NEVER throws. */
100
+ export function normalizeExternalUrl(raw) {
101
+ const trimmed = raw.trim();
102
+ try {
103
+ const u = new URL(trimmed);
104
+ u.protocol = u.protocol.toLowerCase();
105
+ u.hostname = u.hostname.toLowerCase();
106
+ return u.toString();
107
+ }
108
+ catch {
109
+ return trimmed.toLowerCase();
110
+ }
111
+ }
112
+ /**
113
+ * [H-07] The deterministic intake requestId:
114
+ * sha256('takeItDownRequest:v1:' + idempotencyKey + ':' + normalizedTargetKey).
115
+ * A retry with the SAME client idempotencyKey + the SAME target re-derives the SAME
116
+ * id, so the create-if-absent transaction is a no-op and re-returns the same receipt
117
+ * (never double-arms a clock / double-commits a hold).
118
+ */
119
+ export function deterministicRequestId(idempotencyKey, targetKey) {
120
+ return sha256Hex(`${REQUEST_ID_VERSION}:${idempotencyKey}:${targetKey}`);
121
+ }
122
+ /**
123
+ * The opaque public `requestReference` printed on the one-time receipt and stored on the
124
+ * public-status projection. Since the status token was removed, this is a deterministic
125
+ * derivation of the internal `requestId` — a separate sha256 so the raw `requestId` is
126
+ * never recoverable from the reference (which appears on the receipt / projection).
127
+ * 32 hex chars is ample entropy for an opaque, non-enumerable capability.
128
+ */
129
+ export function deriveRequestReference(requestId) {
130
+ return sha256Hex(`takeItDownRequestRef:v1:${requestId}`).slice(0, 32);
131
+ }
132
+ // ===========================================================================
133
+ // Cumulative submission snapshot hash (the immutable receipt fingerprint)
134
+ // ===========================================================================
135
+ /**
136
+ * Deterministic hash of the cumulative request state as of a submission — recorded
137
+ * on `TakeItDownSubmissionV1.cumulativeRequestSnapshotHash`. Built from the SORTED
138
+ * supplied field codes + the normalized target key + the requester role so the same
139
+ * cumulative state always fingerprints identically (append-order independent).
140
+ */
141
+ export function cumulativeSnapshotHash(args) {
142
+ const sorted = [...args.suppliedFieldCodes].sort();
143
+ return sha256Hex(['takeItDownSnapshot:v1', args.requesterRole, args.targetKey, sorted.join(',')].join(SEP));
144
+ }
145
+ // ===========================================================================
146
+ // Privacy-safe target summary (root + public projection — NO narrative / PII)
147
+ // ===========================================================================
148
+ /** A short, non-sensitive surface label per locator kind (no ids, no narrative). */
149
+ export function surfaceLabelFor(locator) {
150
+ switch (locator.kind) {
151
+ case 'mediaAsset':
152
+ return 'Media item';
153
+ case 'hallItem':
154
+ return 'Hall library item';
155
+ case 'squarePost':
156
+ return 'Square Streetz post';
157
+ case 'profileImage':
158
+ return 'Profile image';
159
+ case 'username':
160
+ return 'Username';
161
+ case 'craftSkill':
162
+ return 'Craft skill';
163
+ case 'commissionListing':
164
+ return 'Commission listing';
165
+ case 'audition':
166
+ return 'Audition';
167
+ case 'auditionEntry':
168
+ return 'Audition entry';
169
+ case 'guildInviteMessage':
170
+ return 'Guild invite message';
171
+ case 'chatAttachment':
172
+ return 'Chat attachment';
173
+ case 'guildChatMessage':
174
+ return 'Guild chat message';
175
+ case 'adminWorkMessage':
176
+ return 'Work correspondence message';
177
+ case 'commissionProposal':
178
+ return 'Commission proposal';
179
+ case 'workProject':
180
+ return 'Work project';
181
+ case 'workAsset':
182
+ return 'Work file';
183
+ case 'workRealm':
184
+ return 'Work realm';
185
+ case 'url':
186
+ return 'External link';
187
+ case 'additionalText':
188
+ return 'Described content';
189
+ }
190
+ }
191
+ /** Build the privacy-safe `TargetLocatorSummaryV1` (kind + surface label +
192
+ * whether a TTT-hosted target was server-resolved). NEVER the narrative or ids. */
193
+ export function targetLocatorSummary(locator, hasResolvedTarget) {
194
+ return {
195
+ kind: locator.kind,
196
+ surfaceLabel: surfaceLabelFor(locator),
197
+ hasResolvedTarget,
198
+ };
199
+ }
200
+ /** TTT-hosted locator kinds the intake will synchronously server-resolve +
201
+ * snapshot + temp-hold. `url` / `additionalText` are external/unresolvable: store
202
+ * the locator + submission, invent NO target. */
203
+ const TTT_HOSTED_KINDS = new Set([
204
+ 'mediaAsset',
205
+ 'hallItem',
206
+ 'squarePost',
207
+ 'profileImage',
208
+ 'username',
209
+ 'craftSkill',
210
+ 'commissionListing',
211
+ 'audition',
212
+ 'auditionEntry',
213
+ 'guildInviteMessage',
214
+ 'chatAttachment',
215
+ ]);
216
+ /** True when the locator points at a TTT-hosted surface (server-resolvable). */
217
+ export function isTttHostedLocator(locator) {
218
+ return TTT_HOSTED_KINDS.has(locator.kind);
219
+ }
220
+ // The intake temp hold is placed on the canonical key(s) every destructive guard checks — the
221
+ // content-doc key (`contentDocResourceKey(docPath, 'current')` in `./resource-keys`) + the
222
+ // mediaAsset byte key when the target is media-backed. There is intentionally NO bespoke
223
+ // `nciiTemporaryTarget` key builder here: that namespace was consulted by NO guard, so a hold
224
+ // placed on it never blocked deletion ([H3] void). The route-side mirror's `contentDocCanonicalKey`
225
+ // is likewise NOT ported — it duplicated `contentDocResourceKey(docPath, 'current')`, which is the
226
+ // single key authority.
227
+ //# sourceMappingURL=ncii-intake-derivations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ncii-intake-derivations.js","sourceRoot":"","sources":["../../src/safety/ncii-intake-derivations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import type { MediaAsset, SafetyHoldResourceType } from '../doc-schemas/index.js';
2
+ /** A canonical resource key paired with its sha256 hash (the Firestore doc id). */
3
+ export interface ResourceKey {
4
+ /** The hold `resourceType` this key belongs to (Appendix A3 enum). */
5
+ readonly resourceType: SafetyHoldResourceType;
6
+ /** A natural identifier for the resource, stored on the ref as `resourceId`
7
+ * (human-debuggable; NOT used for hashing — the canonical key is). */
8
+ readonly resourceId: string;
9
+ /** The deterministic canonical key string (Appendix A3). */
10
+ readonly canonicalResourceKey: string;
11
+ /** `sha256(canonicalResourceKey)` hex — the `safetyHoldResources` doc id. */
12
+ readonly resourceKeyHash: string;
13
+ }
14
+ /** sha256-hex of a canonical key string. The single hashing chokepoint. */
15
+ export declare function resourceKeyHash(canonicalResourceKey: string): string;
16
+ /**
17
+ * Firestore content document target = document path + immutable revision.
18
+ * `docPath` must be the canonical full path (e.g. via `toPath(PATH_BUILDERS.x(...))`),
19
+ * NOT a client-supplied path. `revision` pins a mutable doc to a specific version so a
20
+ * post-hold edit cannot slip the bytes out from under the hold; pass the revision/
21
+ * version the report froze.
22
+ */
23
+ export declare function contentDocResourceKey(docPath: string, revision: string | number): ResourceKey;
24
+ /**
25
+ * Storage object target = bucket + key + generation. `generation` pins the exact
26
+ * object version (a re-upload to the same key gets a new generation and is a different
27
+ * physical resource). Pass the generation captured when the hold was placed.
28
+ */
29
+ export declare function storageObjectResourceKey(bucket: string, key: string, generation: string | number): ResourceKey;
30
+ /**
31
+ * Media target. Returns keys for BOTH:
32
+ * 1. the specific `mediaAssetId` (this exact asset/copy), AND
33
+ * 2. its `originLineage.rootIngestId` — when present — as a SEPARATE `mediaAsset`
34
+ * key so a hold can block the ENTIRE incident lineage (every copy/variant that
35
+ * inherited the same root ingest), per Appendix A0/A3 incident-wide blocking.
36
+ *
37
+ * The caller decides which key(s) to place a hold on: a single-asset takedown holds
38
+ * key[0]; an incident-wide block over a CSAM/NCII lineage holds the rootIngest key so
39
+ * every existing AND future copy of the same root is denied. Both keys are `mediaAsset`
40
+ * resourceType (rootIngest is a media identity, not a distinct type — A3 has no
41
+ * separate `rootIngest` type; it is modeled as a mediaAsset key over the root id).
42
+ *
43
+ * Order is stable: index 0 = the asset itself; index 1 (if any) = the rootIngest.
44
+ */
45
+ export declare function mediaAssetResourceKeys(asset: Pick<MediaAsset, 'mediaAssetId' | 'originLineage'>): ResourceKey[];
46
+ /** The mediaAsset key for a bare rootIngestId (no asset doc in hand) — same canonical
47
+ * shape as `mediaAssetResourceKeys(...)`'s index-1 entry, so it hashes identically. */
48
+ export declare function rootIngestResourceKey(rootIngestId: string): ResourceKey;
49
+ /**
50
+ * Chat message-range target = channelId + a sequence/epoch boundary identifying the
51
+ * span of messages held. `messageSeqOrEpoch` is the caller's range identifier (e.g. a
52
+ * sequence number or epoch marker); the SAME range over the same channel must always
53
+ * be passed in the same canonical form by the caller.
54
+ */
55
+ export declare function chatMessageRangeResourceKey(channelId: string, messageSeqOrEpoch: string | number): ResourceKey;
56
+ /** Channel target = channelId. */
57
+ export declare function channelResourceKey(channelId: string): ResourceKey;
58
+ /** Account target = uid. */
59
+ export declare function accountResourceKey(uid: string): ResourceKey;
60
+ //# sourceMappingURL=resource-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-keys.d.ts","sourceRoot":"","sources":["../../src/safety/resource-keys.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AASlF,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;IAC9C;2EACuE;IACvE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,oBAAoB,EAAE,MAAM,GAAG,MAAM,CAEpE;AAiBD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,CAE7F;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GAAG,MAAM,GAC1B,WAAW,CAEb;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,cAAc,GAAG,eAAe,CAAC,GAAG,WAAW,EAAE,CAS/G;AAED;wFACwF;AACxF,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,GAAG,MAAM,GACjC,WAAW,CAOb;AAED,kCAAkC;AAClC,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAEjE;AAED,4BAA4B;AAC5B,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAE3D"}
@@ -0,0 +1,122 @@
1
+ // Canonical safety-hold resource keys (Trust & Safety IMPLEMENTATION_PLAN Appendix A3).
2
+ //
3
+ // A safety hold is keyed by the PHYSICAL resource it protects, not by the case or
4
+ // the request that created it. The `canonicalResourceKey` is a deterministic string
5
+ // built from exactly the identity fields that pin a physical resource:
6
+ //
7
+ // - a Firestore content target = document path + immutable revision/generation
8
+ // - a storage object = bucket + key + generation
9
+ // - a media target = mediaAsset identity (and, incident-wide, its
10
+ // MediaOriginLineageV1.rootIngestId)
11
+ // - a chat message range = channelId + sequence/epoch boundary
12
+ // - a channel = channelId
13
+ // - an account = uid
14
+ //
15
+ // `resourceKeyHash = sha256(canonicalResourceKey)` is the Firestore doc id for both
16
+ // `safetyHoldResources/{resourceKeyHash}` (the O(1) per-flag counter aggregate) and
17
+ // the `{caseId}__{resourceKeyHash}` ref. THE SAME PHYSICAL RESOURCE MUST ALWAYS HASH
18
+ // IDENTICALLY — that is the whole correctness story: every hold over the same bytes
19
+ // joins the same aggregate, and every destructive guard consults the same doc.
20
+ //
21
+ // This is the ONE canonical declaration (Rule 36). Both TTT app TS projects (the Cloud
22
+ // Functions graph AND the App Hosting route graph) import these builders from ttt-core
23
+ // rather than hand-mirroring the format — a re-key would otherwise drift the two runtimes
24
+ // apart. node:crypto sha256 keeps it pure + server-safe (this module lives behind the
25
+ // `./safety` entry, never on the main barrel, so the frontend bundle never loads it).
26
+ //
27
+ // Determinism rules (do not change without a key-version bump):
28
+ // - Format is `v1` + a type tag + the identity fields, joined by the unit-separator
29
+ // control char (\x1f), which cannot appear in a Firestore path, bucket name, key,
30
+ // uid, or channel id. No JSON (key ordering / whitespace is not load-bearing here;
31
+ // a flat separator-joined string is stable by construction).
32
+ // - The type tag prevents cross-type collisions (a contentDoc whose path happens to
33
+ // equal a storage key never shares a hash with that storage object).
34
+ // - A bump to the format string ('v1') is a hold-key migration and is NOT backward
35
+ // compatible — every existing ref/aggregate would re-key. Treat it as a breaking
36
+ // change to the entire hold authority.
37
+ import { createHash } from 'node:crypto';
38
+ /** Format/version tag for every canonical key. Bumping this re-keys ALL holds. */
39
+ const KEY_FORMAT = 'safetyHoldKey/v1';
40
+ /** Unit separator — illegal in every identity field we join, so it is an unambiguous
41
+ * field delimiter that never appears inside a path, key, uid, or channel id. */
42
+ const SEP = '\x1f';
43
+ /** sha256-hex of a canonical key string. The single hashing chokepoint. */
44
+ export function resourceKeyHash(canonicalResourceKey) {
45
+ return createHash('sha256').update(canonicalResourceKey, 'utf8').digest('hex');
46
+ }
47
+ /** Build a {canonicalResourceKey, resourceKeyHash} from a type tag + identity parts. */
48
+ function buildKey(resourceType, resourceId, ...parts) {
49
+ const canonicalResourceKey = [KEY_FORMAT, resourceType, ...parts].join(SEP);
50
+ return {
51
+ resourceType,
52
+ resourceId,
53
+ canonicalResourceKey,
54
+ resourceKeyHash: resourceKeyHash(canonicalResourceKey),
55
+ };
56
+ }
57
+ /**
58
+ * Firestore content document target = document path + immutable revision.
59
+ * `docPath` must be the canonical full path (e.g. via `toPath(PATH_BUILDERS.x(...))`),
60
+ * NOT a client-supplied path. `revision` pins a mutable doc to a specific version so a
61
+ * post-hold edit cannot slip the bytes out from under the hold; pass the revision/
62
+ * version the report froze.
63
+ */
64
+ export function contentDocResourceKey(docPath, revision) {
65
+ return buildKey('contentDoc', docPath, docPath, String(revision));
66
+ }
67
+ /**
68
+ * Storage object target = bucket + key + generation. `generation` pins the exact
69
+ * object version (a re-upload to the same key gets a new generation and is a different
70
+ * physical resource). Pass the generation captured when the hold was placed.
71
+ */
72
+ export function storageObjectResourceKey(bucket, key, generation) {
73
+ return buildKey('storageObject', `${bucket}/${key}`, bucket, key, String(generation));
74
+ }
75
+ /**
76
+ * Media target. Returns keys for BOTH:
77
+ * 1. the specific `mediaAssetId` (this exact asset/copy), AND
78
+ * 2. its `originLineage.rootIngestId` — when present — as a SEPARATE `mediaAsset`
79
+ * key so a hold can block the ENTIRE incident lineage (every copy/variant that
80
+ * inherited the same root ingest), per Appendix A0/A3 incident-wide blocking.
81
+ *
82
+ * The caller decides which key(s) to place a hold on: a single-asset takedown holds
83
+ * key[0]; an incident-wide block over a CSAM/NCII lineage holds the rootIngest key so
84
+ * every existing AND future copy of the same root is denied. Both keys are `mediaAsset`
85
+ * resourceType (rootIngest is a media identity, not a distinct type — A3 has no
86
+ * separate `rootIngest` type; it is modeled as a mediaAsset key over the root id).
87
+ *
88
+ * Order is stable: index 0 = the asset itself; index 1 (if any) = the rootIngest.
89
+ */
90
+ export function mediaAssetResourceKeys(asset) {
91
+ const keys = [
92
+ buildKey('mediaAsset', asset.mediaAssetId, 'asset', asset.mediaAssetId),
93
+ ];
94
+ const rootIngestId = asset.originLineage?.rootIngestId;
95
+ if (rootIngestId) {
96
+ keys.push(buildKey('mediaAsset', rootIngestId, 'rootIngest', rootIngestId));
97
+ }
98
+ return keys;
99
+ }
100
+ /** The mediaAsset key for a bare rootIngestId (no asset doc in hand) — same canonical
101
+ * shape as `mediaAssetResourceKeys(...)`'s index-1 entry, so it hashes identically. */
102
+ export function rootIngestResourceKey(rootIngestId) {
103
+ return buildKey('mediaAsset', rootIngestId, 'rootIngest', rootIngestId);
104
+ }
105
+ /**
106
+ * Chat message-range target = channelId + a sequence/epoch boundary identifying the
107
+ * span of messages held. `messageSeqOrEpoch` is the caller's range identifier (e.g. a
108
+ * sequence number or epoch marker); the SAME range over the same channel must always
109
+ * be passed in the same canonical form by the caller.
110
+ */
111
+ export function chatMessageRangeResourceKey(channelId, messageSeqOrEpoch) {
112
+ return buildKey('chatMessageRange', `${channelId}#${messageSeqOrEpoch}`, channelId, String(messageSeqOrEpoch));
113
+ }
114
+ /** Channel target = channelId. */
115
+ export function channelResourceKey(channelId) {
116
+ return buildKey('channel', channelId, channelId);
117
+ }
118
+ /** Account target = uid. */
119
+ export function accountResourceKey(uid) {
120
+ return buildKey('account', uid, uid);
121
+ }
122
+ //# sourceMappingURL=resource-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-keys.js","sourceRoot":"","sources":["../../src/safety/resource-keys.ts"],"names":[],"mappings":"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"}
@@ -22,4 +22,8 @@ export declare const UpdateGuildInviteStakeSharesInputSchema: z.ZodObject<{
22
22
  newStakeShares: z.ZodNumber;
23
23
  }, z.core.$strict>;
24
24
  export type UpdateGuildInviteStakeSharesInput = z.infer<typeof UpdateGuildInviteStakeSharesInputSchema>;
25
+ export declare const DeleteAdminDispatchInputSchema: z.ZodObject<{
26
+ adminDispatchId: z.ZodString;
27
+ }, z.core.$strip>;
28
+ export type DeleteAdminDispatchInput = z.infer<typeof DeleteAdminDispatchInputSchema>;
25
29
  //# sourceMappingURL=admin-dispatch-actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin-dispatch-actions.d.ts","sourceRoot":"","sources":["../../src/schemas/admin-dispatch-actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,oCAAoC;;;;;;kBAGtC,CAAC;AACZ,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAElG,eAAO,MAAM,mCAAmC;;;;;;;;kBAGrC,CAAC;AACZ,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;AAEhG,eAAO,MAAM,uCAAuC;;;kBAGzC,CAAC;AACZ,MAAM,MAAM,iCAAiC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uCAAuC,CAAC,CAAC"}
1
+ {"version":3,"file":"admin-dispatch-actions.d.ts","sourceRoot":"","sources":["../../src/schemas/admin-dispatch-actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,oCAAoC;;;;;;kBAGtC,CAAC;AACZ,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAElG,eAAO,MAAM,mCAAmC;;;;;;;;kBAGrC,CAAC;AACZ,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;AAEhG,eAAO,MAAM,uCAAuC;;;kBAGzC,CAAC;AACZ,MAAM,MAAM,iCAAiC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uCAAuC,CAAC,CAAC;AAIxG,eAAO,MAAM,8BAA8B;;iBAEzC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC"}
@@ -14,4 +14,9 @@ export const UpdateGuildInviteStakeSharesInputSchema = z.object({
14
14
  guildInviteId: guildInviteIdSchema,
15
15
  newStakeShares: z.number().int().min(1),
16
16
  }).strict();
17
+ // Admin/jr-admin deletes a user's support dispatch thread (`deleteAdminDispatch`). Non-strict
18
+ // posture is carried faithfully from the source callable.
19
+ export const DeleteAdminDispatchInputSchema = z.object({
20
+ adminDispatchId: adminDispatchIdSchema,
21
+ });
17
22
  //# sourceMappingURL=admin-dispatch-actions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin-dispatch-actions.js","sourceRoot":"","sources":["../../src/schemas/admin-dispatch-actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAExE,0FAA0F;AAC1F,6FAA6F;AAC7F,MAAM,CAAC,MAAM,oCAAoC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3D,eAAe,EAAE,qBAAqB;IACtC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;CAC5D,CAAC,CAAC,MAAM,EAAE,CAAC;AAGZ,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1D,aAAa,EAAE,mBAAmB;IAClC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;CAC1D,CAAC,CAAC,MAAM,EAAE,CAAC;AAGZ,MAAM,CAAC,MAAM,uCAAuC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9D,aAAa,EAAE,mBAAmB;IAClC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACxC,CAAC,CAAC,MAAM,EAAE,CAAC"}
1
+ {"version":3,"file":"admin-dispatch-actions.js","sourceRoot":"","sources":["../../src/schemas/admin-dispatch-actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAExE,0FAA0F;AAC1F,6FAA6F;AAC7F,MAAM,CAAC,MAAM,oCAAoC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3D,eAAe,EAAE,qBAAqB;IACtC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;CAC5D,CAAC,CAAC,MAAM,EAAE,CAAC;AAGZ,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1D,aAAa,EAAE,mBAAmB;IAClC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;CAC1D,CAAC,CAAC,MAAM,EAAE,CAAC;AAGZ,MAAM,CAAC,MAAM,uCAAuC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9D,aAAa,EAAE,mBAAmB;IAClC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACxC,CAAC,CAAC,MAAM,EAAE,CAAC;AAGZ,8FAA8F;AAC9F,0DAA0D;AAC1D,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,CAAC,MAAM,CAAC;IACrD,eAAe,EAAE,qBAAqB;CACvC,CAAC,CAAC"}
@@ -179,6 +179,83 @@ export declare const RequireRetitleInputSchema: z.ZodObject<{
179
179
  reason: z.ZodString;
180
180
  }, z.core.$strict>;
181
181
  export type RequireRetitleInput = z.infer<typeof RequireRetitleInputSchema>;
182
+ declare const ModerationShellClearFieldSchema: z.ZodEnum<{
183
+ workingTitle: "workingTitle";
184
+ workingDescription: "workingDescription";
185
+ }>;
186
+ export type ModerationShellClearField = z.infer<typeof ModerationShellClearFieldSchema>;
187
+ export declare const ClearWorkProjectTextInputSchema: z.ZodObject<{
188
+ workProjectId: z.ZodString;
189
+ fields: z.ZodArray<z.ZodEnum<{
190
+ workingTitle: "workingTitle";
191
+ workingDescription: "workingDescription";
192
+ }>>;
193
+ reason: z.ZodString;
194
+ }, z.core.$strict>;
195
+ export type ClearWorkProjectTextInput = z.infer<typeof ClearWorkProjectTextInputSchema>;
196
+ export declare const ClearWorkRealmTextInputSchema: z.ZodObject<{
197
+ workRealmId: z.ZodString;
198
+ fields: z.ZodArray<z.ZodEnum<{
199
+ workingTitle: "workingTitle";
200
+ workingDescription: "workingDescription";
201
+ }>>;
202
+ reason: z.ZodString;
203
+ }, z.core.$strict>;
204
+ export type ClearWorkRealmTextInput = z.infer<typeof ClearWorkRealmTextInputSchema>;
205
+ declare const HallClearFieldSchema: z.ZodEnum<{
206
+ title: "title";
207
+ description: "description";
208
+ content: "content";
209
+ }>;
210
+ export type HallClearField = z.infer<typeof HallClearFieldSchema>;
211
+ export declare const ClearHallContentTextInputSchema: z.ZodObject<{
212
+ hallItemId: z.ZodString;
213
+ workProjectType: z.ZodEnum<{
214
+ Tales: "Tales";
215
+ Tunes: "Tunes";
216
+ Television: "Television";
217
+ }>;
218
+ subItemId: z.ZodOptional<z.ZodString>;
219
+ fields: z.ZodArray<z.ZodEnum<{
220
+ title: "title";
221
+ description: "description";
222
+ content: "content";
223
+ }>>;
224
+ reason: z.ZodString;
225
+ }, z.core.$strict>;
226
+ export type ClearHallContentTextInput = z.infer<typeof ClearHallContentTextInputSchema>;
227
+ export declare const GetLatestHideCascadeInputSchema: z.ZodObject<{
228
+ entityId: z.ZodString;
229
+ targetType: z.ZodEnum<{
230
+ "work-project": "work-project";
231
+ "work-realm": "work-realm";
232
+ }>;
233
+ }, z.core.$strict>;
234
+ export type GetLatestHideCascadeInput = z.infer<typeof GetLatestHideCascadeInputSchema>;
235
+ export declare const ModerateReportedContentInputSchema: z.ZodObject<{
236
+ reportGroupId: z.ZodString;
237
+ targetType: z.ZodEnum<{
238
+ "craft-skill": "craft-skill";
239
+ "commission-listing": "commission-listing";
240
+ "commission-proposal": "commission-proposal";
241
+ "square-streetz-post": "square-streetz-post";
242
+ "profile-picture": "profile-picture";
243
+ "admin-work-message": "admin-work-message";
244
+ "hall-library-item": "hall-library-item";
245
+ audition: "audition";
246
+ "audition-entry": "audition-entry";
247
+ "work-asset": "work-asset";
248
+ }>;
249
+ reportedItemId: z.ZodString;
250
+ parentItemId: z.ZodOptional<z.ZodString>;
251
+ action: z.ZodEnum<{
252
+ remove: "remove";
253
+ hide: "hide";
254
+ restore: "restore";
255
+ }>;
256
+ reason: z.ZodOptional<z.ZodString>;
257
+ }, z.core.$strict>;
258
+ export type ModerateReportedContentInput = z.infer<typeof ModerateReportedContentInputSchema>;
182
259
  export declare const StagedActionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
183
260
  button: z.ZodEnum<{
184
261
  hideContent: "hideContent";
@@ -489,4 +566,5 @@ export declare const GetDeadLettersInputSchema: z.ZodOptional<z.ZodNullable<z.Zo
489
566
  limit: z.ZodOptional<z.ZodNumber>;
490
567
  }, z.core.$strict>>>;
491
568
  export type GetDeadLettersInput = z.infer<typeof GetDeadLettersInputSchema>;
569
+ export {};
492
570
  //# sourceMappingURL=admin.d.ts.map