@selvajs/platform 0.17.0-beta.3 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -28
- package/dist/access/rules.d.ts +20 -26
- package/dist/access/rules.d.ts.map +1 -1
- package/dist/access/rules.js +16 -16
- package/dist/access/rules.js.map +1 -1
- package/dist/auth/interface.d.ts +99 -116
- package/dist/auth/interface.d.ts.map +1 -1
- package/dist/auth/types.d.ts +1 -4
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/bindings/interface.d.ts +19 -32
- package/dist/bindings/interface.d.ts.map +1 -1
- package/dist/bindings/interface.js +6 -12
- package/dist/bindings/interface.js.map +1 -1
- package/dist/computeServer/interface.d.ts +34 -41
- package/dist/computeServer/interface.d.ts.map +1 -1
- package/dist/computeServer/secrets.d.ts +16 -20
- package/dist/computeServer/secrets.d.ts.map +1 -1
- package/dist/computeServer/secrets.js +11 -12
- package/dist/computeServer/secrets.js.map +1 -1
- package/dist/computeServer/types.d.ts +15 -17
- package/dist/computeServer/types.d.ts.map +1 -1
- package/dist/computeServer/types.js.map +1 -1
- package/dist/computeServer/utils.d.ts +8 -14
- package/dist/computeServer/utils.d.ts.map +1 -1
- package/dist/computeServer/utils.js +8 -16
- package/dist/computeServer/utils.js.map +1 -1
- package/dist/config.d.ts +16 -39
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -2
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +12 -19
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +6 -10
- package/dist/context.js.map +1 -1
- package/dist/data/interface.d.ts +32 -47
- package/dist/data/interface.d.ts.map +1 -1
- package/dist/data/interface.js +7 -10
- package/dist/data/interface.js.map +1 -1
- package/dist/definitions/interface.d.ts +24 -31
- package/dist/definitions/interface.d.ts.map +1 -1
- package/dist/definitions/schemas.d.ts.map +1 -1
- package/dist/definitions/schemas.js +6 -9
- package/dist/definitions/schemas.js.map +1 -1
- package/dist/definitions/types.d.ts +26 -42
- package/dist/definitions/types.d.ts.map +1 -1
- package/dist/definitions/types.js +0 -1
- package/dist/definitions/types.js.map +1 -1
- package/dist/errors/interface.d.ts +4 -8
- package/dist/errors/interface.d.ts.map +1 -1
- package/dist/errors/interface.js.map +1 -1
- package/dist/errors.d.ts +2 -5
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -5
- package/dist/errors.js.map +1 -1
- package/dist/events/audit.d.ts +13 -26
- package/dist/events/audit.d.ts.map +1 -1
- package/dist/events/interface.d.ts +17 -33
- package/dist/events/interface.d.ts.map +1 -1
- package/dist/events/interface.js +7 -22
- package/dist/events/interface.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/invites/interface.d.ts +3 -9
- package/dist/invites/interface.d.ts.map +1 -1
- package/dist/invites/types.d.ts +13 -10
- package/dist/invites/types.d.ts.map +1 -1
- package/dist/logging/interface.d.ts +19 -33
- package/dist/logging/interface.d.ts.map +1 -1
- package/dist/logging/interface.js +9 -17
- package/dist/logging/interface.js.map +1 -1
- package/dist/metrics/interface.d.ts +16 -31
- package/dist/metrics/interface.d.ts.map +1 -1
- package/dist/metrics/interface.js +1 -5
- package/dist/metrics/interface.js.map +1 -1
- package/dist/organizations/interface.d.ts +14 -23
- package/dist/organizations/interface.d.ts.map +1 -1
- package/dist/organizations/paths.d.ts +9 -12
- package/dist/organizations/paths.d.ts.map +1 -1
- package/dist/organizations/paths.js +12 -16
- package/dist/organizations/paths.js.map +1 -1
- package/dist/organizations/schemas.d.ts +10 -19
- package/dist/organizations/schemas.d.ts.map +1 -1
- package/dist/organizations/schemas.js +10 -19
- package/dist/organizations/schemas.js.map +1 -1
- package/dist/organizations/types.d.ts +3 -4
- package/dist/organizations/types.d.ts.map +1 -1
- package/dist/pagination.d.ts +13 -21
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js.map +1 -1
- package/dist/permissions/interface.d.ts +12 -21
- package/dist/permissions/interface.d.ts.map +1 -1
- package/dist/permissions/types.d.ts +5 -5
- package/dist/permissions/types.js +5 -5
- package/dist/platformProjects/interface.d.ts +7 -14
- package/dist/platformProjects/interface.d.ts.map +1 -1
- package/dist/platformProjects/types.d.ts +1 -4
- package/dist/platformProjects/types.d.ts.map +1 -1
- package/dist/projects/interface.d.ts +12 -17
- package/dist/projects/interface.d.ts.map +1 -1
- package/dist/shareLinks/interface.d.ts +5 -8
- package/dist/shareLinks/interface.d.ts.map +1 -1
- package/dist/shareLinks/schemas.d.ts.map +1 -1
- package/dist/shareLinks/schemas.js +1 -5
- package/dist/shareLinks/schemas.js.map +1 -1
- package/dist/shareLinks/types.d.ts +5 -6
- package/dist/shareLinks/types.d.ts.map +1 -1
- package/dist/shareLinks/types.js.map +1 -1
- package/dist/solveCache/interface.d.ts +32 -46
- package/dist/solveCache/interface.d.ts.map +1 -1
- package/dist/solveCache/interface.js.map +1 -1
- package/dist/storage/assetClasses.d.ts +16 -24
- package/dist/storage/assetClasses.d.ts.map +1 -1
- package/dist/storage/assetClasses.js +21 -28
- package/dist/storage/assetClasses.js.map +1 -1
- package/dist/storage/cacheBust.d.ts +12 -14
- package/dist/storage/cacheBust.d.ts.map +1 -1
- package/dist/storage/cacheBust.js +12 -14
- package/dist/storage/cacheBust.js.map +1 -1
- package/dist/storage/image.d.ts +9 -13
- package/dist/storage/image.d.ts.map +1 -1
- package/dist/storage/image.js +9 -13
- package/dist/storage/image.js.map +1 -1
- package/dist/userProfile/interface.d.ts +1 -1
- package/dist/userProfile/types.d.ts +1 -5
- package/dist/userProfile/types.d.ts.map +1 -1
- package/dist/userProfile/types.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
import type { RequestContext } from '../context.js';
|
|
2
2
|
import type { PlatformProjectGrant } from './types.js';
|
|
3
3
|
/**
|
|
4
|
-
* Grants for `platform`-visibility projects.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Grants for `platform`-visibility projects. Lets `instance_admin` grant orgs
|
|
5
|
+
* or individual users view-only or view+solve access without creating
|
|
6
|
+
* project membership rows.
|
|
7
7
|
*
|
|
8
8
|
* All deletes are hard-deletes — grants have no downstream references and
|
|
9
9
|
* revocation is immediate.
|
|
10
10
|
*/
|
|
11
11
|
export interface IPlatformProjectGrantStore {
|
|
12
12
|
listByProject(ctx: RequestContext, projectId: string): Promise<PlatformProjectGrant[]>;
|
|
13
|
-
/**
|
|
14
|
-
* Grants for many projects in a single query. Keys are the requested
|
|
15
|
-
* `projectIds`; a project with no grants maps to an empty array.
|
|
16
|
-
*/
|
|
13
|
+
/** Keys are the requested `projectIds`; a project with no grants maps to an empty array. */
|
|
17
14
|
listByProjects(ctx: RequestContext, projectIds: readonly string[]): Promise<Map<string, PlatformProjectGrant[]>>;
|
|
18
15
|
create(ctx: RequestContext, grant: PlatformProjectGrant): Promise<void>;
|
|
19
16
|
delete(ctx: RequestContext, id: string): Promise<void>;
|
|
20
|
-
/**
|
|
21
|
-
* Cascade hook: drop every grant for a project. Called by `deleteProject`.
|
|
22
|
-
* No-op when none exist.
|
|
23
|
-
*/
|
|
17
|
+
/** Cascade hook called by `deleteProject`. */
|
|
24
18
|
deleteByProject(ctx: RequestContext, projectId: string): Promise<void>;
|
|
25
19
|
/**
|
|
26
|
-
* Cascade hook
|
|
27
|
-
* `
|
|
28
|
-
* exist.
|
|
20
|
+
* Cascade hook called by `deleteOrg`: drops every org grant whose
|
|
21
|
+
* `granteeId === orgId`. User grants are identity-scoped and remain.
|
|
29
22
|
*/
|
|
30
23
|
deleteByGranteeOrg(ctx: RequestContext, orgId: string): Promise<void>;
|
|
31
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/platformProjects/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,WAAW,0BAA0B;IAC1C,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACvF
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/platformProjects/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,WAAW,0BAA0B;IAC1C,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACvF,4FAA4F;IAC5F,cAAc,CACb,GAAG,EAAE,cAAc,EACnB,UAAU,EAAE,SAAS,MAAM,EAAE,GAC3B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC,CAAC;IAChD,MAAM,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,MAAM,CAAC,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,8CAA8C;IAC9C,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE;;;OAGG;IACH,kBAAkB,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE"}
|
|
@@ -5,16 +5,13 @@ export type PlatformProjectGranteeType = 'org' | 'user';
|
|
|
5
5
|
*
|
|
6
6
|
* - `granteeType: 'org'` → applies to all members of that org
|
|
7
7
|
* - `granteeType: 'user'` → applies to that specific user regardless of org
|
|
8
|
-
* - `canSolve: false` → schema fetch / view only; submit-solve is blocked
|
|
9
|
-
* - `canSolve: true` → view + solve
|
|
10
|
-
*
|
|
11
|
-
* Grants are hard-deleted on revocation — no soft-delete.
|
|
12
8
|
*/
|
|
13
9
|
export interface PlatformProjectGrant {
|
|
14
10
|
id: string;
|
|
15
11
|
projectId: string;
|
|
16
12
|
granteeType: PlatformProjectGranteeType;
|
|
17
13
|
granteeId: string;
|
|
14
|
+
/** false = view/schema only; true = view + solve. */
|
|
18
15
|
canSolve: boolean;
|
|
19
16
|
createdBy: string;
|
|
20
17
|
createdAt: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/platformProjects/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,0BAA0B,GAAG,KAAK,GAAG,MAAM,CAAC;AAExD
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/platformProjects/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,0BAA0B,GAAG,KAAK,GAAG,MAAM,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,0BAA0B,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -12,31 +12,26 @@ export interface IProjectStore {
|
|
|
12
12
|
getProjectBySlug(ctx: RequestContext, orgId: string, slug: string): Promise<Project | null>;
|
|
13
13
|
createProject(ctx: RequestContext, project: Project): Promise<void>;
|
|
14
14
|
updateProject(ctx: RequestContext, id: string, patch: Partial<Pick<Project, 'name' | 'slug' | 'description' | 'visibility' | 'autoJoinOnUpload'>>): Promise<void>;
|
|
15
|
-
/**
|
|
16
|
-
* Soft-delete the project. Cascades to project members and definitions.
|
|
17
|
-
* Definition versions and share links cascade through the definition delete.
|
|
18
|
-
*/
|
|
15
|
+
/** Soft-delete. Cascades to project members and definitions (and, through the definition delete, to definition versions and share links). */
|
|
19
16
|
deleteProject(ctx: RequestContext, id: string): Promise<void>;
|
|
20
17
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
18
|
+
* Reactivates a soft-deleted project by org + slug: clears `deleted_at`
|
|
19
|
+
* and reactivates the owner's `project_members` row. Returns `null` if no
|
|
20
|
+
* tombstone with that slug exists.
|
|
24
21
|
*
|
|
25
|
-
* Use this when `createProject`
|
|
26
|
-
*
|
|
27
|
-
* even though `getProjectBySlug` returns null for tombstones.
|
|
22
|
+
* Use this when `createProject` hits a duplicate-key error on a
|
|
23
|
+
* soft-deleted slug — the unique constraint isn't conditional, so it
|
|
24
|
+
* blocks creation even though `getProjectBySlug` returns null for tombstones.
|
|
28
25
|
*/
|
|
29
26
|
reactivateProject(ctx: RequestContext, orgId: string, slug: string): Promise<Project | null>;
|
|
30
27
|
listProjectMembers(ctx: RequestContext, projectId: string, opts?: ListOptions): Promise<Page<ProjectMember>>;
|
|
31
28
|
getProjectMember(ctx: RequestContext, projectId: string, userId: string): Promise<ProjectMember | null>;
|
|
32
29
|
/**
|
|
33
|
-
* One user's membership row across many projects, in a single query
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* `
|
|
37
|
-
*
|
|
38
|
-
* maps to `null` rather than being absent, so callers can distinguish
|
|
39
|
-
* "checked, not a member" from "never asked".
|
|
30
|
+
* One user's membership row across many projects, in a single query —
|
|
31
|
+
* avoids one round-trip per project when evaluating `canView` over a list.
|
|
32
|
+
* Keys are the requested `projectIds`; a project the user isn't a member of
|
|
33
|
+
* maps to `null` rather than being absent, distinguishing "checked, not a
|
|
34
|
+
* member" from "never asked".
|
|
40
35
|
*/
|
|
41
36
|
getProjectMembersFor(ctx: RequestContext, projectIds: readonly string[], userId: string): Promise<Map<string, ProjectMember | null>>;
|
|
42
37
|
addProjectMember(ctx: RequestContext, member: ProjectMember): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/projects/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAE7B,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7F,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACrE,gBAAgB,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC5F,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,aAAa,CACZ,GAAG,EAAE,cAAc,EACnB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,OAAO,CACb,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,YAAY,GAAG,kBAAkB,CAAC,CAClF,GACC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/projects/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAE7B,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7F,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACrE,gBAAgB,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC5F,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,aAAa,CACZ,GAAG,EAAE,cAAc,EACnB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,OAAO,CACb,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,YAAY,GAAG,kBAAkB,CAAC,CAClF,GACC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,6IAA6I;IAC7I,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D;;;;;;;;OAQG;IACH,iBAAiB,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAG7F,kBAAkB,CACjB,GAAG,EAAE,cAAc,EACnB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IAChC,gBAAgB,CACf,GAAG,EAAE,cAAc,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACjC;;;;;;OAMG;IACH,oBAAoB,CACnB,GAAG,EAAE,cAAc,EACnB,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9C,gBAAgB,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,uBAAuB,CACtB,GAAG,EAAE,cAAc,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW,GACf,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,mBAAmB,CAAC,GAAG,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3F"}
|
|
@@ -9,22 +9,19 @@ import type { ShareLink } from './types.js';
|
|
|
9
9
|
* Reads filter `revokedAt IS NULL` defensively.
|
|
10
10
|
*/
|
|
11
11
|
export interface IShareLinkStore {
|
|
12
|
-
/**
|
|
12
|
+
/** Caller has already hashed the raw token. */
|
|
13
13
|
create(ctx: RequestContext, link: ShareLink): Promise<void>;
|
|
14
14
|
/** Newest first by `createdAt`. Excludes revoked links. */
|
|
15
15
|
listByDefinition(ctx: RequestContext, definitionId: string, opts?: ListOptions): Promise<Page<ShareLink>>;
|
|
16
16
|
getById(ctx: RequestContext, id: string): Promise<ShareLink | null>;
|
|
17
|
-
/**
|
|
18
|
-
* Lookup by HMAC hash. Returns null when the link doesn't exist OR is
|
|
19
|
-
* revoked OR its parent definition is soft-deleted.
|
|
20
|
-
*/
|
|
17
|
+
/** Returns null when the link doesn't exist, is revoked, or its parent definition is soft-deleted. */
|
|
21
18
|
getByTokenHash(ctx: RequestContext, tokenHash: string): Promise<ShareLink | null>;
|
|
22
19
|
/** Soft-delete (set `revokedAt`). Idempotent. */
|
|
23
20
|
revoke(ctx: RequestContext, id: string): Promise<void>;
|
|
24
21
|
/**
|
|
25
|
-
* Atomic check-and-increment
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* Atomic check-and-increment; must be a single statement, since
|
|
23
|
+
* read-then-write races under load. Returns the new `solveCount`, or
|
|
24
|
+
* null when the cap was reached. `null` maxSolves means uncapped.
|
|
28
25
|
*/
|
|
29
26
|
tryIncrementSolveCount(ctx: RequestContext, id: string): Promise<number | null>;
|
|
30
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/shareLinks/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC/B
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/shareLinks/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC/B,+CAA+C;IAC/C,MAAM,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,2DAA2D;IAC3D,gBAAgB,CACf,GAAG,EAAE,cAAc,EACnB,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IACpE,sGAAsG;IACtG,cAAc,CAAC,GAAG,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAClF,iDAAiD;IACjD,MAAM,CAAC,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD;;;;OAIG;IACH,sBAAsB,CAAC,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAChF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/shareLinks/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;GAGG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/shareLinks/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;GAGG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;iBAOrC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
|
|
@@ -8,12 +8,8 @@ export const CreateShareLinkInputSchema = z.object({
|
|
|
8
8
|
channel: DefinitionChannelSchema.default('live'),
|
|
9
9
|
name: z.string().max(128).optional(),
|
|
10
10
|
allowSolve: z.boolean().default(true),
|
|
11
|
-
/**
|
|
12
|
-
* Null explicitly removes the cap. Omitted = apply default — null is the
|
|
13
|
-
* minter's deliberate "uncap" choice.
|
|
14
|
-
*/
|
|
11
|
+
/** Null is the minter's deliberate "uncap" choice; omitted applies the default cap. */
|
|
15
12
|
maxSolves: z.number().int().min(1).nullable().optional(),
|
|
16
|
-
/** Optional ISO timestamp. Resolution compares to `now()`. */
|
|
17
13
|
expiresAt: z.iso.datetime().nullable().optional()
|
|
18
14
|
});
|
|
19
15
|
//# sourceMappingURL=schemas.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/shareLinks/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,OAAO,EAAE,uBAAuB,CAAC,OAAO,CAAC,MAAM,CAAC;IAChD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACpC,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACrC
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/shareLinks/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,OAAO,EAAE,uBAAuB,CAAC,OAAO,CAAC,MAAM,CAAC;IAChD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACpC,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACrC,uFAAuF;IACvF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACxD,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACjD,CAAC,CAAC"}
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
import type { DefinitionChannel } from '../definitions/types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Per-definition token granting access to one (definitionId, channel)
|
|
4
|
-
* without an account. The
|
|
5
|
-
*
|
|
4
|
+
* without an account. The plaintext token is shown to the minter exactly
|
|
5
|
+
* once; `tokenHash` is the HMAC stored at rest.
|
|
6
6
|
*/
|
|
7
7
|
export interface ShareLink {
|
|
8
8
|
id: string;
|
|
9
9
|
definitionId: string;
|
|
10
10
|
channel: DefinitionChannel;
|
|
11
|
-
/** HMAC of the raw token. Lookup hashes the supplied token, then matches. */
|
|
12
11
|
tokenHash: string;
|
|
13
|
-
/**
|
|
12
|
+
/** e.g. "Demo for Acme". */
|
|
14
13
|
name?: string;
|
|
15
14
|
createdBy: string;
|
|
16
15
|
createdAt: string;
|
|
17
16
|
/** Null = never expires. */
|
|
18
17
|
expiresAt?: string | null;
|
|
19
|
-
/** Non-null = revoked.
|
|
18
|
+
/** Non-null = revoked. */
|
|
20
19
|
revokedAt?: string | null;
|
|
21
20
|
/** false = view/schema only; true = solve allowed. */
|
|
22
21
|
allowSolve: boolean;
|
|
23
|
-
/**
|
|
22
|
+
/** Null = unlimited. */
|
|
24
23
|
maxSolves?: number | null;
|
|
25
24
|
solveCount: number;
|
|
26
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shareLinks/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shareLinks/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,sDAAsD;IACtD,UAAU,EAAE,OAAO,CAAC;IACpB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,OAAO,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/shareLinks/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/shareLinks/types.ts"],"names":[],"mappings":"AA2BA;;;;GAIG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,IAAI,CAAC"}
|
|
@@ -4,75 +4,61 @@ import type { RequestContext } from '../context.js';
|
|
|
4
4
|
* inputKey)` where `inputKey` is a wide (SHA-256) hash of the transformed input
|
|
5
5
|
* tree plus the solve-affecting config subset. A hit skips compute entirely.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* outlived the in-process implementation that used to sit behind it.
|
|
7
|
+
* Design contract:
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* - **
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* same buffer Redis would, so a hit stays near-CPU-free in either backend and
|
|
17
|
-
* there is no serialization drift between impls.
|
|
9
|
+
* - **Async from day one.** The in-memory backend returns promises too, so a
|
|
10
|
+
* network store (Redis) drops in later without any call site changing shape.
|
|
11
|
+
* - **Entries are opaque bytes** — the pre-gzipped response envelope plus a
|
|
12
|
+
* small metadata header. The backend never inspects them, so a hit stays
|
|
13
|
+
* near-CPU-free in either backend and there's no serialization drift between
|
|
14
|
+
* implementations.
|
|
18
15
|
* - **Best-effort.** `get` may miss at any time (restart, eviction, network
|
|
19
|
-
* blip); `set` may silently drop. Correctness
|
|
20
|
-
* this is what makes
|
|
21
|
-
*
|
|
16
|
+
* blip); `set` may silently drop. Correctness never depends on cache presence
|
|
17
|
+
* — this is what makes the no-TTL/versionId keying safe under any eviction
|
|
18
|
+
* policy.
|
|
22
19
|
* - **Per-definition quota, passed at write time.** `set` carries
|
|
23
|
-
* `maxEntriesForDefinition` so the backend holds no policy, only data.
|
|
24
|
-
* is LRU *within* the definition: a slider-heavy definition churns
|
|
25
|
-
* entries, not everyone else's.
|
|
26
|
-
* - **Version keying
|
|
27
|
-
* fresh keyspace; rollback re-hits old entries; there
|
|
20
|
+
* `maxEntriesForDefinition` so the backend holds no policy, only data.
|
|
21
|
+
* Eviction is LRU *within* the definition: a slider-heavy definition churns
|
|
22
|
+
* only its own entries, not everyone else's.
|
|
23
|
+
* - **Version keying means no invalidation.** Publishing mints a new
|
|
24
|
+
* `versionId` → fresh keyspace; rollback re-hits old entries; there's
|
|
25
|
+
* nothing to invalidate.
|
|
28
26
|
*/
|
|
29
27
|
/** The parts that address a cached solve. All four are folded into the stored key. */
|
|
30
28
|
export interface SolveCacheKey {
|
|
31
29
|
/**
|
|
32
|
-
* Owning org (defense-in-depth against cross-tenant reads).
|
|
33
|
-
*
|
|
34
|
-
*
|
|
30
|
+
* Owning org (defense-in-depth against cross-tenant reads). Always a real
|
|
31
|
+
* org, never null — the app only builds a `SolveCacheKey` for org-scoped
|
|
32
|
+
* live-channel solves; remote-URL solves (no org) never reach this path.
|
|
35
33
|
*/
|
|
36
34
|
orgId: string;
|
|
37
35
|
/** The definition guid — the quota scope. */
|
|
38
36
|
definitionId: string;
|
|
39
|
-
/** The immutable version id
|
|
37
|
+
/** The immutable version id. */
|
|
40
38
|
versionId: string;
|
|
41
|
-
/**
|
|
42
|
-
* Wide hash of the transformed input tree + solve-affecting config subset
|
|
43
|
-
* (SHA-256 hex; see the pipeline's key builder). This is the only part that
|
|
44
|
-
* varies per solve of a given version.
|
|
45
|
-
*/
|
|
39
|
+
/** SHA-256 hex hash of the transformed input tree + solve-affecting config subset. */
|
|
46
40
|
inputKey: string;
|
|
47
41
|
}
|
|
48
42
|
/** Options for a write; carries the per-definition quota so the backend stays stateless. */
|
|
49
43
|
export interface SolveCacheSetOptions {
|
|
50
44
|
/**
|
|
51
|
-
* Max cached entries this definition may retain
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* the resolved quota is `0` (caching off), so this is always `>= 1`.
|
|
45
|
+
* Max cached entries this definition may retain (`solveCacheLimit` on the
|
|
46
|
+
* definition record). Always `>= 1` — callers must not call `set` when the
|
|
47
|
+
* resolved quota is `0` (caching off).
|
|
55
48
|
*/
|
|
56
49
|
maxEntriesForDefinition: number;
|
|
57
50
|
}
|
|
58
51
|
/**
|
|
59
|
-
* Durable solve-result cache — the seam a
|
|
60
|
-
*
|
|
61
|
-
* There is deliberately no implementation today. The in-process one that used to
|
|
62
|
-
* live behind this interface was redundant: it was a `Map` in the same heap as
|
|
63
|
-
* the scheduler's own response cache, which is consulted first, so it could only
|
|
64
|
-
* ever serve what that cache had already evicted. It was deleted; this interface
|
|
65
|
-
* was not, because it is the piece that is correct for scaling.
|
|
52
|
+
* Durable solve-result cache — the seam a shared backend mounts on.
|
|
66
53
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* proxy and
|
|
70
|
-
*
|
|
71
|
-
* by contract, so a network backend drops in without any call site changing shape.
|
|
54
|
+
* No implementation ships today: the app runs on `adapter-node`, one
|
|
55
|
+
* long-lived process, where in-process caching already works. Run N instances
|
|
56
|
+
* behind a proxy and the in-process hit rate divides by N — that's when Redis
|
|
57
|
+
* mounts here.
|
|
72
58
|
*
|
|
73
|
-
* Implementations
|
|
74
|
-
*
|
|
75
|
-
*
|
|
59
|
+
* Implementations must not throw — both methods sit on the hot path of every
|
|
60
|
+
* live solve. A backend failure resolves as a miss (`get`) or a silent drop
|
|
61
|
+
* (`set`); it never becomes a request error.
|
|
76
62
|
*/
|
|
77
63
|
export interface ISolveResultCache {
|
|
78
64
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/solveCache/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/solveCache/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,sFAAsF;AACtF,MAAM,WAAW,aAAa;IAC7B;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,4FAA4F;AAC5F,MAAM,WAAW,oBAAoB;IACpC;;;;OAIG;IACH,uBAAuB,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IACjC;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACzE;;;OAGG;IACH,GAAG,CACF,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,oBAAoB,GACxB,OAAO,CAAC,IAAI,CAAC,CAAC;CACjB;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,iBAAiB;IACvD,GAAG,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAG1E,GAAG,CACR,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,oBAAoB,GACzB,OAAO,CAAC,IAAI,CAAC;CAChB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/solveCache/interface.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/solveCache/interface.ts"],"names":[],"mappings":"AAoFA;;;;GAIG;AACH,MAAM,OAAO,oBAAoB;IAChC,KAAK,CAAC,GAAG,CAAC,IAAoB,EAAE,IAAmB;QAClD,OAAO,IAAI,CAAC;IACb,CAAC;IACD,KAAK,CAAC,GAAG,CACR,IAAoB,EACpB,IAAmB,EACnB,MAAkB,EAClB,KAA2B,IACV,CAAC;CACnB"}
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* How a stored asset is allowed to be read.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* asset type is one entry in {@link ASSET_CLASSES} rather than a new route.
|
|
2
|
+
* How a stored asset is allowed to be read. A property of the asset *class*
|
|
3
|
+
* (its path prefix), never of the individual file — a new asset type is one
|
|
4
|
+
* entry in {@link ASSET_CLASSES} rather than a new route.
|
|
6
5
|
*
|
|
7
|
-
* - `public` — anyone, including logged-out visitors
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* from the path and runs an org-membership check. Used for org-private docs
|
|
12
|
-
* (e.g. pricing sheets) once they exist.
|
|
13
|
-
* - `project` — members of the owning project only. The route resolves the
|
|
14
|
-
* definition guid → its project and runs the project-view check. Used for
|
|
15
|
-
* definition cover images and other per-definition blobs.
|
|
6
|
+
* - `public` — anyone, including logged-out visitors (branding: logo, favicon).
|
|
7
|
+
* - `org` — members of the owning org only; route resolves orgId from the path.
|
|
8
|
+
* - `project` — members of the owning project only; route resolves the
|
|
9
|
+
* definition guid to its project (cover images, per-definition blobs).
|
|
16
10
|
*/
|
|
17
11
|
export type AssetVisibility = 'public' | 'org' | 'project';
|
|
18
12
|
/**
|
|
@@ -37,21 +31,19 @@ export interface AssetMatch {
|
|
|
37
31
|
readonly scopeId: string | null;
|
|
38
32
|
}
|
|
39
33
|
/**
|
|
40
|
-
* The closed registry of servable asset classes.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* default-deny: a new blob type is opt-in by adding an entry here.
|
|
34
|
+
* The closed registry of servable asset classes. Patterns are mutually
|
|
35
|
+
* exclusive by prefix, order doesn't matter. Anything matching no class is
|
|
36
|
+
* unservable (the route 404s) — default-deny, so a new blob type is opt-in.
|
|
44
37
|
*/
|
|
45
38
|
export declare const ASSET_CLASSES: readonly AssetClass[];
|
|
46
39
|
/**
|
|
47
|
-
*
|
|
48
|
-
* class matches (or the path is unsafe).
|
|
49
|
-
*
|
|
50
|
-
*
|
|
40
|
+
* Classifies a storage path into its asset class and scope id, or null when
|
|
41
|
+
* no class matches (or the path is unsafe). `getPublicUrl` and the serving
|
|
42
|
+
* route both consult this so URL generation and authorization never drift
|
|
43
|
+
* apart.
|
|
51
44
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* authorizes against it (`scope !== 'none'`); public classes report null.
|
|
45
|
+
* `scopeId` is null for `scope: 'none'` classes even when the pattern
|
|
46
|
+
* captures an id (e.g. `org-branding` captures orgId but is public).
|
|
55
47
|
*/
|
|
56
48
|
export declare function classifyAssetPath(storagePath: string): AssetMatch | null;
|
|
57
49
|
/** True when the path belongs to a `public` asset class (CDN-servable, no auth). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetClasses.d.ts","sourceRoot":"","sources":["../../src/storage/assetClasses.ts"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"assetClasses.d.ts","sourceRoot":"","sources":["../../src/storage/assetClasses.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;AAE3D;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AAEpD,MAAM,WAAW,UAAU;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAiBD;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,UAAU,EAqB9C,CAAC;AAkBF;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAQxE;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE9D"}
|
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
import { ALL_ORG_ASSET_KINDS } from '../organizations/schemas.js';
|
|
2
2
|
import { COVER_IMAGE_EXTENSIONS } from '../definitions/types.js';
|
|
3
|
-
//
|
|
4
|
-
// schema enum so adding a kind there extends this pattern automatically.
|
|
3
|
+
// Built from the schema enum so a new branding kind extends this pattern automatically.
|
|
5
4
|
const BRANDING_KINDS = ALL_ORG_ASSET_KINDS.join('|');
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// cover format there propagates here instead of silently 404ing legit covers.
|
|
5
|
+
// Derived from COVER_IMAGE_EXTENSIONS so a new cover format propagates here
|
|
6
|
+
// instead of silently 404ing legit covers.
|
|
9
7
|
const COVER_EXTS = COVER_IMAGE_EXTENSIONS.map((ext) => ext.replace(/^\./, '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// shape — kept in sync with `UUID_REGEX` in definitions/schemas.ts.
|
|
8
|
+
// SAFE_SEGMENT mirrors the assertSafeKey alphabet in the path helpers
|
|
9
|
+
// (traversal/empty segments are rejected separately by hasUnsafeSegment);
|
|
10
|
+
// GUID is kept in sync with UUID_REGEX in definitions/schemas.ts.
|
|
14
11
|
const SAFE_SEGMENT = String.raw `[A-Za-z0-9._-]+`;
|
|
15
12
|
const GUID = String.raw `[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`;
|
|
16
13
|
/**
|
|
17
|
-
* The closed registry of servable asset classes.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* default-deny: a new blob type is opt-in by adding an entry here.
|
|
14
|
+
* The closed registry of servable asset classes. Patterns are mutually
|
|
15
|
+
* exclusive by prefix, order doesn't matter. Anything matching no class is
|
|
16
|
+
* unservable (the route 404s) — default-deny, so a new blob type is opt-in.
|
|
21
17
|
*/
|
|
22
18
|
export const ASSET_CLASSES = [
|
|
23
19
|
{
|
|
@@ -40,14 +36,12 @@ export const ASSET_CLASSES = [
|
|
|
40
36
|
}
|
|
41
37
|
];
|
|
42
38
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* the registry is the read-side gate, those are the write-side gate, and both
|
|
50
|
-
* forbid the same segments so a path that can't be *written* can't be *read*.
|
|
39
|
+
* Rejects traversal, empty, or backslash segments before a path can match a
|
|
40
|
+
* class. The permissive segment alphabet (`[A-Za-z0-9._-]+`) admits a bare
|
|
41
|
+
* `.` or `..` as a whole segment, which would otherwise let
|
|
42
|
+
* `orgs/../branding/logo.webp` classify as public branding with `..`
|
|
43
|
+
* captured as the orgId. Mirrors `assertSafeKey` on the write side, so a path
|
|
44
|
+
* that can't be written can't be read either.
|
|
51
45
|
*/
|
|
52
46
|
function hasUnsafeSegment(storagePath) {
|
|
53
47
|
if (storagePath.includes('\\'))
|
|
@@ -59,14 +53,13 @@ function hasUnsafeSegment(storagePath) {
|
|
|
59
53
|
return false;
|
|
60
54
|
}
|
|
61
55
|
/**
|
|
62
|
-
*
|
|
63
|
-
* class matches (or the path is unsafe).
|
|
64
|
-
*
|
|
65
|
-
*
|
|
56
|
+
* Classifies a storage path into its asset class and scope id, or null when
|
|
57
|
+
* no class matches (or the path is unsafe). `getPublicUrl` and the serving
|
|
58
|
+
* route both consult this so URL generation and authorization never drift
|
|
59
|
+
* apart.
|
|
66
60
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* authorizes against it (`scope !== 'none'`); public classes report null.
|
|
61
|
+
* `scopeId` is null for `scope: 'none'` classes even when the pattern
|
|
62
|
+
* captures an id (e.g. `org-branding` captures orgId but is public).
|
|
70
63
|
*/
|
|
71
64
|
export function classifyAssetPath(storagePath) {
|
|
72
65
|
if (hasUnsafeSegment(storagePath))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetClasses.js","sourceRoot":"","sources":["../../src/storage/assetClasses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"assetClasses.js","sourceRoot":"","sources":["../../src/storage/assetClasses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAsCjE,wFAAwF;AACxF,MAAM,cAAc,GAAG,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAErD,4EAA4E;AAC5E,2CAA2C;AAC3C,MAAM,UAAU,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACrD,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAC7D,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,sEAAsE;AACtE,0EAA0E;AAC1E,kEAAkE;AAClE,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAA,iBAAiB,CAAC;AACjD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAA,8DAA8D,CAAC;AAEtF;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAA0B;IACnD;QACC,EAAE,EAAE,cAAc;QAClB,UAAU,EAAE,QAAQ;QACpB,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,IAAI,MAAM,CAClB,MAAM,CAAC,GAAG,CAAA,WAAW,YAAY,mBAAmB,cAAc,UAAU,CAC5E;KACD;IACD;QACC,EAAE,EAAE,aAAa;QACjB,UAAU,EAAE,KAAK;QACjB,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAA,WAAW,YAAY,eAAe,YAAY,GAAG,CAAC;KACpF;IACD;QACC,EAAE,EAAE,kBAAkB;QACtB,UAAU,EAAE,SAAS;QACrB,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAA,kBAAkB,IAAI,gBAAgB,UAAU,IAAI,EAAE,GAAG,CAAC;KACxF;CACD,CAAC;AAEF;;;;;;;GAOG;AACH,SAAS,gBAAgB,CAAC,WAAmB;IAC5C,IAAI,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9C,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;IACxE,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACpD,IAAI,gBAAgB,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACpD,OAAO,iBAAiB,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,QAAQ,CAAC;AACtE,CAAC"}
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Appends a cache-busting token to a stored-asset URL.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* distinct URL (forcing a refetch) while letting unchanged assets stay cached.
|
|
4
|
+
* `IStorageProvider.put` upserts, so a re-upload keeps the same storage path
|
|
5
|
+
* and public URL — a browser/CDN caching the old bytes under that URL keeps
|
|
6
|
+
* serving them past the TTL, which reads as "the replace didn't work."
|
|
7
|
+
* Appending a token that only changes with the content gives each version a
|
|
8
|
+
* distinct URL, forcing a refetch, while unchanged assets stay cached.
|
|
10
9
|
*
|
|
11
|
-
* Generic over asset kind
|
|
12
|
-
*
|
|
13
|
-
* `
|
|
14
|
-
*
|
|
15
|
-
* client-cache key and needs no route support.
|
|
10
|
+
* Generic over asset kind — pass whatever tracks the blob's version (content
|
|
11
|
+
* hash, `updatedAt`, a counter). The serving route ignores the query string
|
|
12
|
+
* (SvelteKit's `[...path]` param never includes it), so this needs no route
|
|
13
|
+
* support.
|
|
16
14
|
*
|
|
17
|
-
* Empty/whitespace tokens
|
|
18
|
-
*
|
|
15
|
+
* Empty/whitespace tokens return the URL unchanged, so a missing token
|
|
16
|
+
* degrades to "no cache-bust" rather than `?v=`.
|
|
19
17
|
*/
|
|
20
18
|
export declare function withCacheBust(url: string, token: string | number | undefined | null): string;
|
|
21
19
|
//# sourceMappingURL=cacheBust.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cacheBust.d.ts","sourceRoot":"","sources":["../../src/storage/cacheBust.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cacheBust.d.ts","sourceRoot":"","sources":["../../src/storage/cacheBust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAM5F"}
|