@ttt-productions/ttt-core 0.79.95 → 0.79.96

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.
@@ -37,4 +37,10 @@ export declare const AdminCreateMediaGrantInputSchema: z.ZodDiscriminatedUnion<[
37
37
  mediaAssetId: z.ZodString;
38
38
  }, z.core.$strict>], "scopeKind">;
39
39
  export type AdminCreateMediaGrantInput = z.infer<typeof AdminCreateMediaGrantInputSchema>;
40
+ /** Both grant callables answer the same signed grant, bound to the caller. */
41
+ export declare const CreateMediaGrantResultSchema: z.ZodObject<{
42
+ grant: z.ZodString;
43
+ expiresAt: z.ZodNumber;
44
+ }, z.core.$strict>;
45
+ export type CreateMediaGrantResult = z.infer<typeof CreateMediaGrantResultSchema>;
40
46
  //# sourceMappingURL=media.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/schemas/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAoFxB,4DAA4D;AAC5D,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;iCAOtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,kFAAkF;AAClF,eAAO,MAAM,gCAAgC;;;;;;;;;;iCAI3C,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC"}
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/schemas/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAoFxB,4DAA4D;AAC5D,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;iCAOtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,kFAAkF;AAClF,eAAO,MAAM,gCAAgC;;;;;;;;;;iCAI3C,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAE1F,8EAA8E;AAC9E,eAAO,MAAM,4BAA4B;;;kBAI9B,CAAC;AACZ,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC"}
@@ -77,4 +77,10 @@ export const AdminCreateMediaGrantInputSchema = z.discriminatedUnion('scopeKind'
77
77
  AdminSupportGrantScopeSchema,
78
78
  AdminReviewGrantScopeSchema,
79
79
  ]);
80
+ /** Both grant callables answer the same signed grant, bound to the caller. */
81
+ export const CreateMediaGrantResultSchema = z.object({
82
+ grant: z.string().min(1),
83
+ /** Epoch ms; a client refreshes under it. */
84
+ expiresAt: z.number().int().positive(),
85
+ }).strict();
80
86
  //# sourceMappingURL=media.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/schemas/media.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport {\n workProjectIdSchema,\n guildInviteIdSchema,\n workFileFolderIdSchema,\n commissionListingIdSchema,\n commissionProposalIdSchema,\n adminDispatchIdSchema,\n reportGroupIdSchema,\n mediaAssetIdSchema,\n workRealmIdSchema,\n realmFileShareRequestIdSchema,\n} from './atoms.js';\n\n// Scoped-media grant requests for the gateway Worker: the scoped tier is a session cookie plus a\n// user-bound grant. These are the CLIENT-CALLED wire contracts of the two grant callables, so they\n// live here, not in the functions repo. The EXACT Firestore permission check happens in the\n// callable; a schema only pins the shape. A custom folder's bytes must be unreachable outside its\n// view trade-professions, so `workFileFolder` is the EXACT folder scope (not the whole Work grant);\n// guildInvite / adminSupport are the two per-CONVERSATION scopes that serve Conversation Files\n// (guild chat channels have none — no guildChannel scope).\n//\n// Admin authority is a callable of its own (BACKEND-004): `createMediaGrant` serves a\n// participant, `adminCreateMediaGrant` an admin acting in review or support, and spends a\n// single-use App Check token. Each scope is declared once and joins the union of every callable\n// that serves it.\n\n// Pre-publish content media of a work project (hall covers / sub-item media). A participant needs\n// project read membership; an admin reaches it from a review surface. Work FILES use the tighter\n// workFileFolder scope.\nconst WorkProjectGrantScopeSchema = z.object({\n scopeKind: z.literal('workProject'),\n workProjectId: workProjectIdSchema,\n}).strict();\n\n// One work-project FILE FOLDER — the EXACT folder scope, NOT the whole-Work grant.\nconst WorkFileFolderGrantScopeSchema = z.object({\n scopeKind: z.literal('workFileFolder'),\n workProjectId: workProjectIdSchema,\n workFileFolderId: workFileFolderIdSchema,\n}).strict();\n\n// One commission proposal's media — proposal author or listing-side manager.\nconst CommissionProposalGrantScopeSchema = z.object({\n scopeKind: z.literal('commissionProposal'),\n commissionListingId: commissionListingIdSchema,\n commissionProposalId: commissionProposalIdSchema,\n}).strict();\n\n// A guild-INVITE conversation's Conversation File (no workProjectId to match on).\nconst GuildInviteGrantScopeSchema = z.object({\n scopeKind: z.literal('guildInvite'),\n guildInviteId: guildInviteIdSchema,\n}).strict();\n\n// An admin-support THREAD's Conversation File — per-thread scope keyed by adminDispatchId: the\n// thread owner through `createMediaGrant`, the admin side through `adminCreateMediaGrant`.\nconst AdminSupportGrantScopeSchema = z.object({\n scopeKind: z.literal('adminSupport'),\n adminDispatchId: adminDispatchIdSchema,\n}).strict();\n\n// Moderation reveal of ONE reported asset, bound to its report group — full or jr admin only. The\n// callable verifies the asset belongs to the group's derived target (or its frozen report-time\n// snapshot) before minting; the grant is bound to exactly that asset id, short TTL. Admins see\n// reported things BECAUSE they were reported — this is never a browse-any-asset scope.\nconst AdminReviewGrantScopeSchema = z.object({\n scopeKind: z.literal('adminReview'),\n reportGroupId: reportGroupIdSchema,\n mediaAssetId: mediaAssetIdSchema,\n}).strict();\n\n// A Realm steward's preview of ONE Work file awaiting their promotion decision — the Realm's\n// current steward only, and only while the file is still pending under this request id in this\n// Realm (the callable re-checks all three at mint). The request id is the one the steward's queue\n// row showed, so a decided, withdrawn, or superseded request mints nothing. The grant names\n// exactly that asset and never reveals a hidden one.\nconst RealmFilePreviewGrantScopeSchema = z.object({\n scopeKind: z.literal('realmFilePreview'),\n workRealmId: workRealmIdSchema,\n mediaAssetId: mediaAssetIdSchema,\n realmFileShareRequestId: realmFileShareRequestIdSchema,\n}).strict();\n\n/** The `createMediaGrant` input: a participant's scopes. */\nexport const CreateMediaGrantInputSchema = z.discriminatedUnion('scopeKind', [\n WorkProjectGrantScopeSchema,\n WorkFileFolderGrantScopeSchema,\n CommissionProposalGrantScopeSchema,\n GuildInviteGrantScopeSchema,\n AdminSupportGrantScopeSchema,\n RealmFilePreviewGrantScopeSchema,\n]);\nexport type CreateMediaGrantInput = z.infer<typeof CreateMediaGrantInputSchema>;\n\n/** The `adminCreateMediaGrant` input: the scopes an admin reaches as an admin. */\nexport const AdminCreateMediaGrantInputSchema = z.discriminatedUnion('scopeKind', [\n WorkProjectGrantScopeSchema,\n AdminSupportGrantScopeSchema,\n AdminReviewGrantScopeSchema,\n]);\nexport type AdminCreateMediaGrantInput = z.infer<typeof AdminCreateMediaGrantInputSchema>;\n"]}
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/schemas/media.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport {\n workProjectIdSchema,\n guildInviteIdSchema,\n workFileFolderIdSchema,\n commissionListingIdSchema,\n commissionProposalIdSchema,\n adminDispatchIdSchema,\n reportGroupIdSchema,\n mediaAssetIdSchema,\n workRealmIdSchema,\n realmFileShareRequestIdSchema,\n} from './atoms.js';\n\n// Scoped-media grant requests for the gateway Worker: the scoped tier is a session cookie plus a\n// user-bound grant. These are the CLIENT-CALLED wire contracts of the two grant callables, so they\n// live here, not in the functions repo. The EXACT Firestore permission check happens in the\n// callable; a schema only pins the shape. A custom folder's bytes must be unreachable outside its\n// view trade-professions, so `workFileFolder` is the EXACT folder scope (not the whole Work grant);\n// guildInvite / adminSupport are the two per-CONVERSATION scopes that serve Conversation Files\n// (guild chat channels have none — no guildChannel scope).\n//\n// Admin authority is a callable of its own (BACKEND-004): `createMediaGrant` serves a\n// participant, `adminCreateMediaGrant` an admin acting in review or support, and spends a\n// single-use App Check token. Each scope is declared once and joins the union of every callable\n// that serves it.\n\n// Pre-publish content media of a work project (hall covers / sub-item media). A participant needs\n// project read membership; an admin reaches it from a review surface. Work FILES use the tighter\n// workFileFolder scope.\nconst WorkProjectGrantScopeSchema = z.object({\n scopeKind: z.literal('workProject'),\n workProjectId: workProjectIdSchema,\n}).strict();\n\n// One work-project FILE FOLDER — the EXACT folder scope, NOT the whole-Work grant.\nconst WorkFileFolderGrantScopeSchema = z.object({\n scopeKind: z.literal('workFileFolder'),\n workProjectId: workProjectIdSchema,\n workFileFolderId: workFileFolderIdSchema,\n}).strict();\n\n// One commission proposal's media — proposal author or listing-side manager.\nconst CommissionProposalGrantScopeSchema = z.object({\n scopeKind: z.literal('commissionProposal'),\n commissionListingId: commissionListingIdSchema,\n commissionProposalId: commissionProposalIdSchema,\n}).strict();\n\n// A guild-INVITE conversation's Conversation File (no workProjectId to match on).\nconst GuildInviteGrantScopeSchema = z.object({\n scopeKind: z.literal('guildInvite'),\n guildInviteId: guildInviteIdSchema,\n}).strict();\n\n// An admin-support THREAD's Conversation File — per-thread scope keyed by adminDispatchId: the\n// thread owner through `createMediaGrant`, the admin side through `adminCreateMediaGrant`.\nconst AdminSupportGrantScopeSchema = z.object({\n scopeKind: z.literal('adminSupport'),\n adminDispatchId: adminDispatchIdSchema,\n}).strict();\n\n// Moderation reveal of ONE reported asset, bound to its report group — full or jr admin only. The\n// callable verifies the asset belongs to the group's derived target (or its frozen report-time\n// snapshot) before minting; the grant is bound to exactly that asset id, short TTL. Admins see\n// reported things BECAUSE they were reported — this is never a browse-any-asset scope.\nconst AdminReviewGrantScopeSchema = z.object({\n scopeKind: z.literal('adminReview'),\n reportGroupId: reportGroupIdSchema,\n mediaAssetId: mediaAssetIdSchema,\n}).strict();\n\n// A Realm steward's preview of ONE Work file awaiting their promotion decision — the Realm's\n// current steward only, and only while the file is still pending under this request id in this\n// Realm (the callable re-checks all three at mint). The request id is the one the steward's queue\n// row showed, so a decided, withdrawn, or superseded request mints nothing. The grant names\n// exactly that asset and never reveals a hidden one.\nconst RealmFilePreviewGrantScopeSchema = z.object({\n scopeKind: z.literal('realmFilePreview'),\n workRealmId: workRealmIdSchema,\n mediaAssetId: mediaAssetIdSchema,\n realmFileShareRequestId: realmFileShareRequestIdSchema,\n}).strict();\n\n/** The `createMediaGrant` input: a participant's scopes. */\nexport const CreateMediaGrantInputSchema = z.discriminatedUnion('scopeKind', [\n WorkProjectGrantScopeSchema,\n WorkFileFolderGrantScopeSchema,\n CommissionProposalGrantScopeSchema,\n GuildInviteGrantScopeSchema,\n AdminSupportGrantScopeSchema,\n RealmFilePreviewGrantScopeSchema,\n]);\nexport type CreateMediaGrantInput = z.infer<typeof CreateMediaGrantInputSchema>;\n\n/** The `adminCreateMediaGrant` input: the scopes an admin reaches as an admin. */\nexport const AdminCreateMediaGrantInputSchema = z.discriminatedUnion('scopeKind', [\n WorkProjectGrantScopeSchema,\n AdminSupportGrantScopeSchema,\n AdminReviewGrantScopeSchema,\n]);\nexport type AdminCreateMediaGrantInput = z.infer<typeof AdminCreateMediaGrantInputSchema>;\n\n/** Both grant callables answer the same signed grant, bound to the caller. */\nexport const CreateMediaGrantResultSchema = z.object({\n grant: z.string().min(1),\n /** Epoch ms; a client refreshes under it. */\n expiresAt: z.number().int().positive(),\n}).strict();\nexport type CreateMediaGrantResult = z.infer<typeof CreateMediaGrantResultSchema>;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/ttt-core",
3
- "version": "0.79.95",
3
+ "version": "0.79.96",
4
4
  "description": "Core types, Firestore path constants, and shared constants for TTT Productions",
5
5
  "repository": {
6
6
  "type": "git",