@astram/identity 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/auth-facts-keys.d.ts +16 -0
  2. package/dist/auth-facts-keys.d.ts.map +1 -1
  3. package/dist/auth-facts-keys.js +26 -10
  4. package/dist/cross-tenant-grant.object.d.ts +2 -2
  5. package/dist/cross-tenant-grant.object.d.ts.map +1 -1
  6. package/dist/cross-tenant-grant.object.js +5 -2
  7. package/dist/features/authz/catalog-bootstrap.provider.d.ts +4 -1
  8. package/dist/features/authz/catalog-bootstrap.provider.d.ts.map +1 -1
  9. package/dist/features/authz/catalog-bootstrap.provider.js +37 -6
  10. package/dist/features/cross-tenant/cross-tenant-grant-read.service.d.ts +6 -5
  11. package/dist/features/cross-tenant/cross-tenant-grant-read.service.d.ts.map +1 -1
  12. package/dist/features/cross-tenant/cross-tenant-grant-read.service.js +6 -5
  13. package/dist/features/files/files.controller.d.ts +27 -0
  14. package/dist/features/files/files.controller.d.ts.map +1 -0
  15. package/dist/features/files/files.controller.js +94 -0
  16. package/dist/features/files/files.service.d.ts +87 -0
  17. package/dist/features/files/files.service.d.ts.map +1 -0
  18. package/dist/features/files/files.service.js +311 -0
  19. package/dist/features/identity-feature.module.d.ts.map +1 -1
  20. package/dist/features/identity-feature.module.js +37 -11
  21. package/dist/features/policy/policy.service.d.ts +2 -1
  22. package/dist/features/policy/policy.service.d.ts.map +1 -1
  23. package/dist/features/policy/policy.service.js +15 -0
  24. package/dist/features/share/share.service.d.ts +19 -2
  25. package/dist/features/share/share.service.d.ts.map +1 -1
  26. package/dist/features/share/share.service.js +36 -2
  27. package/dist/index.d.ts +9 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +13 -1
  30. package/dist/objects.d.ts.map +1 -1
  31. package/dist/objects.js +2 -0
  32. package/dist/record-share.object.d.ts +1 -1
  33. package/dist/record-share.object.d.ts.map +1 -1
  34. package/dist/record-share.object.js +4 -1
  35. package/dist/service-account.object.d.ts +3 -2
  36. package/dist/service-account.object.d.ts.map +1 -1
  37. package/dist/service-account.object.js +4 -2
  38. package/dist/stored-file.object.d.ts +35 -0
  39. package/dist/stored-file.object.d.ts.map +1 -0
  40. package/dist/stored-file.object.js +94 -0
  41. package/migrations/1710000000022-CreateStoredFile.cjs +43 -0
  42. package/package.json +8 -4
@@ -1,3 +1,19 @@
1
+ import type { ObjectTypeInput } from '@astram/engine';
2
+ /** The auth-facts key universe for identity's objects plus a consumer's `extraObjects`. */
3
+ export interface IdentityAuthKeys {
4
+ /** Every action key: pass as `ShieldModule.forRoot({ identityActionKeys })`. */
5
+ readonly actionKeys: string[];
6
+ /** The control-plane subset: pass as `ShieldModule.forRoot({ identityControlPlaneKeys })`. */
7
+ readonly controlPlaneKeys: string[];
8
+ }
9
+ /**
10
+ * Build the auth-facts key universe from identity's objects plus `extraObjects` (pass the same
11
+ * array as `IdentityFeatureModule.forRoot({ extraObjects })`). Same registry bridge as the record
12
+ * authorization, so the keys match decide() and the permission catalog exactly.
13
+ */
14
+ export declare function buildIdentityAuthKeys(extraObjects?: readonly ObjectTypeInput[]): IdentityAuthKeys;
15
+ /** Identity's own action keys (no consumer types; see {@link buildIdentityAuthKeys}). */
1
16
  export declare const identityAuthActionKeys: readonly string[];
17
+ /** Identity's own control-plane keys (no consumer types; see {@link buildIdentityAuthKeys}). */
2
18
  export declare const identityControlPlaneKeys: readonly string[];
3
19
  //# sourceMappingURL=auth-facts-keys.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-facts-keys.d.ts","sourceRoot":"","sources":["../src/auth-facts-keys.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAEZ,CAAC;AAEzC,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAGd,CAAC"}
1
+ {"version":3,"file":"auth-facts-keys.d.ts","sourceRoot":"","sources":["../src/auth-facts-keys.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD,2FAA2F;AAC3F,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC;IAC9B,8FAA8F;IAC9F,QAAQ,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,GAAE,SAAS,eAAe,EAAO,GAC5C,gBAAgB,CAQlB;AAID,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAA4B,CAAC;AAEjF,gGAAgG;AAChG,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAAkC,CAAC"}
@@ -1,24 +1,40 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.identityControlPlaneKeys = exports.identityAuthActionKeys = void 0;
4
+ exports.buildIdentityAuthKeys = buildIdentityAuthKeys;
4
5
  /**
5
- * The framework identity permission-key universe, projected once from `identityObjects` via
6
+ * The framework identity permission-key universe, projected from `identityObjects` via
6
7
  * `@astram/guard`'s registry bridge. Exported for the consumer to pass into
7
8
  * `ShieldModule.forRoot({ auth: true, identityActionKeys, identityControlPlaneKeys })` — so the
8
9
  * auth-facts adapter (in guard) can expand `identity:*` grants + union root's control-plane keys
9
10
  * WITHOUT guard importing this package (the sanctioned graph is identity → guard).
10
11
  *
12
+ * A consumer that registers its own object types passes the SAME list it gives
13
+ * `IdentityFeatureModule.forRoot({ extraObjects })` to {@link buildIdentityAuthKeys} (KI #70), so
14
+ * `/auth/facts` covers the same key universe decide() and the permission catalog use.
15
+ *
11
16
  * ⚠ NO MODULE-INIT CYCLE: `identityObjects` is imported from the leaf `./objects.js` (NOT from
12
17
  * `./index.js`, which re-exports THIS file). So the array is fully initialized before the
13
- * `buildIdentityModuleRegistry(...)` call below runs at module-eval time.
18
+ * `buildIdentityAuthKeys()` call below runs at module-eval time.
14
19
  */
15
20
  const guard_1 = require("@astram/guard");
16
21
  const objects_js_1 = require("./objects.js");
17
- const registry = (0, guard_1.buildIdentityModuleRegistry)(objects_js_1.identityObjects);
18
- exports.identityAuthActionKeys = registry
19
- .listActions()
20
- .map((a) => a.permissionKey);
21
- exports.identityControlPlaneKeys = registry
22
- .listActions()
23
- .filter((a) => a.plane === 'control')
24
- .map((a) => a.permissionKey);
22
+ /**
23
+ * Build the auth-facts key universe from identity's objects plus `extraObjects` (pass the same
24
+ * array as `IdentityFeatureModule.forRoot({ extraObjects })`). Same registry bridge as the record
25
+ * authorization, so the keys match decide() and the permission catalog exactly.
26
+ */
27
+ function buildIdentityAuthKeys(extraObjects = []) {
28
+ const actions = (0, guard_1.buildIdentityModuleRegistry)([...objects_js_1.identityObjects, ...extraObjects]).listActions();
29
+ return {
30
+ actionKeys: actions.map((a) => a.permissionKey),
31
+ controlPlaneKeys: actions
32
+ .filter((a) => a.plane === 'control')
33
+ .map((a) => a.permissionKey),
34
+ };
35
+ }
36
+ const identityOnly = buildIdentityAuthKeys();
37
+ /** Identity's own action keys (no consumer types; see {@link buildIdentityAuthKeys}). */
38
+ exports.identityAuthActionKeys = identityOnly.actionKeys;
39
+ /** Identity's own control-plane keys (no consumer types; see {@link buildIdentityAuthKeys}). */
40
+ exports.identityControlPlaneKeys = identityOnly.controlPlaneKeys;
@@ -13,8 +13,8 @@
13
13
  *
14
14
  * Mirrors `membership-posting.object.ts`'s shape (system, no trusted columns needed
15
15
  * beyond the PK) — the engine's `validateAccess` requires `table` + at least one
16
- * `@Field`; the PK satisfies that. Action vocabulary is NOT the CRUD `IDENTITY_ACTIONS`
17
- * — see `@astram/guard`'s `identity-actions.ts`'s `actionsFor('cross_tenant_grant')` ->
16
+ * `@Field`; the PK satisfies that. Action vocabulary is NOT the CRUD verbs: it opts out
17
+ * (`crudActions: false`, ADR-0038) and declares exactly `@astram/guard`'s
18
18
  * `CROSS_TENANT_GRANT_ACTIONS` (`share`/`accept`/`revoke`).
19
19
  *
20
20
  * Ported from astram3's frozen
@@ -1 +1 @@
1
- {"version":3,"file":"cross-tenant-grant.object.d.ts","sourceRoot":"","sources":["../src/cross-tenant-grant.object.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAOa,gBAAgB;IAE3B,IAAI,EAAG,MAAM,CAAC;IAGd,gBAAgB,EAAG,MAAM,CAAC;IAG1B,iBAAiB,EAAG,MAAM,CAAC;CAC5B"}
1
+ {"version":3,"file":"cross-tenant-grant.object.d.ts","sourceRoot":"","sources":["../src/cross-tenant-grant.object.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBASa,gBAAgB;IAE3B,IAAI,EAAG,MAAM,CAAC;IAGd,gBAAgB,EAAG,MAAM,CAAC;IAG1B,iBAAiB,EAAG,MAAM,CAAC;CAC5B"}
@@ -11,6 +11,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.CrossTenantGrant = void 0;
13
13
  const engine_1 = require("@astram/engine");
14
+ const guard_1 = require("@astram/guard");
14
15
  /** The physical schema `cross_tenant_grant` lives in (migration 1710000000011). */
15
16
  const SCHEMA = 'shield_authz';
16
17
  /**
@@ -28,8 +29,8 @@ const SCHEMA = 'shield_authz';
28
29
  *
29
30
  * Mirrors `membership-posting.object.ts`'s shape (system, no trusted columns needed
30
31
  * beyond the PK) — the engine's `validateAccess` requires `table` + at least one
31
- * `@Field`; the PK satisfies that. Action vocabulary is NOT the CRUD `IDENTITY_ACTIONS`
32
- * — see `@astram/guard`'s `identity-actions.ts`'s `actionsFor('cross_tenant_grant')` ->
32
+ * `@Field`; the PK satisfies that. Action vocabulary is NOT the CRUD verbs: it opts out
33
+ * (`crudActions: false`, ADR-0038) and declares exactly `@astram/guard`'s
33
34
  * `CROSS_TENANT_GRANT_ACTIONS` (`share`/`accept`/`revoke`).
34
35
  *
35
36
  * Ported from astram3's frozen
@@ -59,6 +60,8 @@ exports.CrossTenantGrant = CrossTenantGrant = __decorate([
59
60
  table: 'cross_tenant_grant',
60
61
  schema: SCHEMA,
61
62
  access: { plane: 'control', system: true },
63
+ crudActions: false,
64
+ actions: guard_1.CROSS_TENANT_GRANT_ACTIONS,
62
65
  }),
63
66
  (0, engine_1.PrimaryKey)({ kind: 'uuid', column: 'ctg_uuid' })
64
67
  ], CrossTenantGrant);
@@ -1,5 +1,6 @@
1
1
  import { type OnApplicationBootstrap } from '@nestjs/common';
2
2
  import { DiscoveryService, MetadataScanner, Reflector } from '@nestjs/core';
3
+ import { type RecordAuthorizationInputs } from '@astram/guard';
3
4
  import type { ObjectType } from '@astram/engine';
4
5
  import { CatalogReconcileJob } from './catalog-reconcile.job.js';
5
6
  import { AccessBundleReconcileJob } from './access-bundle-reconcile.job.js';
@@ -23,8 +24,10 @@ export declare class CatalogBootstrapProvider implements OnApplicationBootstrap
23
24
  private readonly accessBundleJob;
24
25
  private readonly scopeClosure;
25
26
  private readonly registrations;
27
+ private readonly recordAuthorization;
28
+ private readonly logger;
26
29
  private timer;
27
- constructor(discovery: DiscoveryService, scanner: MetadataScanner, reflector: Reflector, job: CatalogReconcileJob, accessBundleJob: AccessBundleReconcileJob, scopeClosure: ScopeClosureService, registrations: readonly ObjectType[]);
30
+ constructor(discovery: DiscoveryService, scanner: MetadataScanner, reflector: Reflector, job: CatalogReconcileJob, accessBundleJob: AccessBundleReconcileJob, scopeClosure: ScopeClosureService, registrations: readonly ObjectType[], recordAuthorization: RecordAuthorizationInputs);
28
31
  onApplicationBootstrap(): Promise<void>;
29
32
  /** Rebuild the scope closure; a failure is logged loudly (never silently swallowed) but does
30
33
  * not abort boot or a cron tick — the reconcile is idempotent and retried next interval. */
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-bootstrap.provider.d.ts","sourceRoot":"","sources":["../../../src/features/authz/catalog-bootstrap.provider.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsB,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAO5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAKxE;;;;;;;;;;GAUG;AACH,qBACa,wBAAyB,YAAW,sBAAsB;IAInE,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAVhC,OAAO,CAAC,KAAK,CAA+B;gBAGzB,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,mBAAmB,EACxB,eAAe,EAAE,wBAAwB,EACzC,YAAY,EAAE,mBAAmB,EAEjC,aAAa,EAAE,SAAS,UAAU,EAAE;IAGjD,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAsC7C;iGAC6F;YAC/E,qBAAqB;CAOpC"}
1
+ {"version":3,"file":"catalog-bootstrap.provider.d.ts","sourceRoot":"","sources":["../../../src/features/authz/catalog-bootstrap.provider.ts"],"names":[],"mappings":"AAIA,OAAO,EAA8B,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAKL,KAAK,yBAAyB,EAC/B,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAKxE;;;;;;;;;;GAUG;AACH,qBACa,wBAAyB,YAAW,sBAAsB;IAKnE,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAE9B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IAbtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;IACpE,OAAO,CAAC,KAAK,CAA+B;gBAGzB,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,mBAAmB,EACxB,eAAe,EAAE,wBAAwB,EACzC,YAAY,EAAE,mBAAmB,EAEjC,aAAa,EAAE,SAAS,UAAU,EAAE,EAEpC,mBAAmB,EAAE,yBAAyB;IAG3D,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAyE7C;iGAC6F;YAC/E,qBAAqB;CAOpC"}
@@ -11,6 +11,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
+ var CatalogBootstrapProvider_1;
14
15
  Object.defineProperty(exports, "__esModule", { value: true });
15
16
  exports.CatalogBootstrapProvider = void 0;
16
17
  // Ported from astram3 `server/src/features/authz/catalog-bootstrap.provider.ts`.
@@ -37,7 +38,7 @@ const RECONCILE_INTERVAL_MS = 60 * 60 * 1000; // hourly; honors DISABLE_ALL_CRON
37
38
  * health controller injects — so verify, the post-boot pass, and the endpoint all share
38
39
  * one job. This provider owns only the boot verify + the schedule.
39
40
  */
40
- let CatalogBootstrapProvider = class CatalogBootstrapProvider {
41
+ let CatalogBootstrapProvider = CatalogBootstrapProvider_1 = class CatalogBootstrapProvider {
41
42
  discovery;
42
43
  scanner;
43
44
  reflector;
@@ -45,8 +46,10 @@ let CatalogBootstrapProvider = class CatalogBootstrapProvider {
45
46
  accessBundleJob;
46
47
  scopeClosure;
47
48
  registrations;
49
+ recordAuthorization;
50
+ logger = new common_1.Logger(CatalogBootstrapProvider_1.name);
48
51
  timer = null;
49
- constructor(discovery, scanner, reflector, job, accessBundleJob, scopeClosure, registrations) {
52
+ constructor(discovery, scanner, reflector, job, accessBundleJob, scopeClosure, registrations, recordAuthorization) {
50
53
  this.discovery = discovery;
51
54
  this.scanner = scanner;
52
55
  this.reflector = reflector;
@@ -54,11 +57,38 @@ let CatalogBootstrapProvider = class CatalogBootstrapProvider {
54
57
  this.accessBundleJob = accessBundleJob;
55
58
  this.scopeClosure = scopeClosure;
56
59
  this.registrations = registrations;
60
+ this.recordAuthorization = recordAuthorization;
57
61
  }
58
62
  async onApplicationBootstrap() {
59
- const registry = (0, guard_1.buildIdentityModuleRegistry)(this.registrations);
63
+ // ONE key universe (KI #70): verify against the registry decide(), the grant ceiling and the
64
+ // catalog reconcile job all use (identity objects + the consumer's `extraObjects`).
65
+ const registry = this.recordAuthorization.registry;
60
66
  const inventoryScanner = new guard_1.OperationInventoryScanner(this.discovery, this.scanner, this.reflector);
61
- const inventory = inventoryScanner.scan(MODULE_KEY);
67
+ const scanned = inventoryScanner.scan(MODULE_KEY);
68
+ // A type registered with `EngineModule.forFeature` but not passed as `extraObjects` is
69
+ // unknown to decide() (`resource_not_registered`), so every gated access to it is denied
70
+ // and its keys are not catalogued. Before KI #70 verify ran over the engine registrations,
71
+ // so such routes booted; keep them booting (no new boot failure for existing consumers) but
72
+ // say loudly that they can never be allowed.
73
+ const engineOnly = this.registrations.filter((r) => registry.resolveObjectType(r.typeKey) === undefined);
74
+ let inventory = scanned;
75
+ if (engineOnly.length > 0) {
76
+ const engineOnlyKeys = new Set((0, guard_1.buildIdentityModuleRegistry)(engineOnly)
77
+ .listActions()
78
+ .map((a) => a.permissionKey));
79
+ const denied = scanned.operations.filter((op) => op.permissionKey !== undefined && engineOnlyKeys.has(op.permissionKey));
80
+ this.logger.warn(`object type(s) ${engineOnly.map((r) => r.typeKey).join(', ')} are registered with ` +
81
+ 'EngineModule.forFeature but not in IdentityFeatureModule.forRoot({ extraObjects }): ' +
82
+ 'decide() denies every gated access to them and their keys are not catalogued' +
83
+ (denied.length > 0
84
+ ? `; always-denied routes: ${denied.map((op) => op.operationId).join(', ')}`
85
+ : '') +
86
+ '. Add them to extraObjects.');
87
+ inventory = {
88
+ ...scanned,
89
+ operations: scanned.operations.filter((op) => !denied.includes(op)),
90
+ };
91
+ }
62
92
  // Fail-closed (ADR-0002): a route that can't be gated aborts boot.
63
93
  new guard_1.CatalogReconciler().verifyGatable(inventory, registry);
64
94
  // Mutating reconcile runs AFTER boot (not blocking, not fail-closed).
@@ -97,13 +127,14 @@ let CatalogBootstrapProvider = class CatalogBootstrapProvider {
97
127
  }
98
128
  };
99
129
  exports.CatalogBootstrapProvider = CatalogBootstrapProvider;
100
- exports.CatalogBootstrapProvider = CatalogBootstrapProvider = __decorate([
130
+ exports.CatalogBootstrapProvider = CatalogBootstrapProvider = CatalogBootstrapProvider_1 = __decorate([
101
131
  (0, common_1.Injectable)(),
102
132
  __param(6, (0, common_1.Inject)(engine_1.ENGINE_ALL_REGISTRATIONS)),
133
+ __param(7, (0, common_1.Inject)(guard_1.SHIELD_RECORD_AUTHORIZATION)),
103
134
  __metadata("design:paramtypes", [core_1.DiscoveryService,
104
135
  core_1.MetadataScanner,
105
136
  core_1.Reflector,
106
137
  catalog_reconcile_job_js_1.CatalogReconcileJob,
107
138
  access_bundle_reconcile_job_js_1.AccessBundleReconcileJob,
108
- scope_closure_service_js_1.ScopeClosureService, Array])
139
+ scope_closure_service_js_1.ScopeClosureService, Array, Object])
109
140
  ], CatalogBootstrapProvider);
@@ -59,11 +59,12 @@ export declare class CrossTenantGrantReadService {
59
59
  * surface uses, so a future tenantScoped type is picked up the same way it becomes
60
60
  * shareable.
61
61
  * @param actionsByType per-typeKey action vocabulary for the offerable-types read
62
- * (decision 1: "the actions per type come from the type's own action set"). Callers
63
- * pass `actionsFor`, which defaults every type to the CRUD `IDENTITY_ACTIONS` except
64
- * a type with its own override (e.g. `cross_tenant_grant` -> share/accept/revoke) —
65
- * the single source every action-vocabulary consumer uses, so a per-type set can
66
- * never drift between callers.
62
+ * (decision 1: "the actions per type come from the type's own action set"). The
63
+ * module passes its registration-based lookup (`effectiveActions` over the same
64
+ * `[...identityObjects, ...extraObjects]`, ADR-0038): CRUD plus a type's declared
65
+ * extras, or exactly its declared list for `crudActions: false` (e.g.
66
+ * `cross_tenant_grant` -> share/accept/revoke) — the single source every
67
+ * action-vocabulary consumer uses, so a per-type set can never drift between callers.
67
68
  */
68
69
  constructor(pool: Pool, offerableTypeInputs: readonly ObjectTypeInput[], actionsByType: (typeKey: string) => readonly string[]);
69
70
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"cross-tenant-grant-read.service.d.ts","sourceRoot":"","sources":["../../../src/features/cross-tenant/cross-tenant-grant-read.service.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAMtD,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,iFAAiF;AACjF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,6FAA6F;AAC7F,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA+FD,qBACa,2BAA2B;IAiBpC,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAlBhC;;;;;;;;;;;;;;OAcG;gBAEgB,IAAI,EAAE,IAAI,EACV,mBAAmB,EAAE,SAAS,eAAe,EAAE,EAC/C,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE;IAGxE;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IA0B1E;;;;;OAKG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAyBzD;;;;;;;OAOG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAyBjE;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;IASzB;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIzC;;;;;;;OAOG;IACG,kBAAkB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAWxD"}
1
+ {"version":3,"file":"cross-tenant-grant-read.service.d.ts","sourceRoot":"","sources":["../../../src/features/cross-tenant/cross-tenant-grant-read.service.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAMtD,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,iFAAiF;AACjF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,6FAA6F;AAC7F,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA+FD,qBACa,2BAA2B;IAkBpC,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAnBhC;;;;;;;;;;;;;;;OAeG;gBAEgB,IAAI,EAAE,IAAI,EACV,mBAAmB,EAAE,SAAS,eAAe,EAAE,EAC/C,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE;IAGxE;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IA0B1E;;;;;OAKG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAyBzD;;;;;;;OAOG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAyBjE;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;IASzB;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIzC;;;;;;;OAOG;IACG,kBAAkB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAWxD"}
@@ -120,11 +120,12 @@ let CrossTenantGrantReadService = class CrossTenantGrantReadService {
120
120
  * surface uses, so a future tenantScoped type is picked up the same way it becomes
121
121
  * shareable.
122
122
  * @param actionsByType per-typeKey action vocabulary for the offerable-types read
123
- * (decision 1: "the actions per type come from the type's own action set"). Callers
124
- * pass `actionsFor`, which defaults every type to the CRUD `IDENTITY_ACTIONS` except
125
- * a type with its own override (e.g. `cross_tenant_grant` -> share/accept/revoke) —
126
- * the single source every action-vocabulary consumer uses, so a per-type set can
127
- * never drift between callers.
123
+ * (decision 1: "the actions per type come from the type's own action set"). The
124
+ * module passes its registration-based lookup (`effectiveActions` over the same
125
+ * `[...identityObjects, ...extraObjects]`, ADR-0038): CRUD plus a type's declared
126
+ * extras, or exactly its declared list for `crudActions: false` (e.g.
127
+ * `cross_tenant_grant` -> share/accept/revoke) — the single source every
128
+ * action-vocabulary consumer uses, so a per-type set can never drift between callers.
128
129
  */
129
130
  constructor(pool, offerableTypeInputs, actionsByType) {
130
131
  this.pool = pool;
@@ -0,0 +1,27 @@
1
+ import { StreamableFile } from '@nestjs/common';
2
+ import { FilesService } from './files.service.js';
3
+ /**
4
+ * `filename*` value for a stored name: C0 controls and DEL dropped, the rest UTF-8 percent-encoded
5
+ * byte by byte (a lone surrogate becomes U+FFFD via `Buffer.from`, so this never throws). Quotes,
6
+ * CR, LF, `;` and spaces are always encoded, so the name cannot split or extend the header.
7
+ */
8
+ export declare function rfc5987FileName(name: string): string;
9
+ /**
10
+ * FilesController — the framework download route `GET /files/:uuid` (file-storage SPEC §3, §5 K2).
11
+ *
12
+ * - Gated on `stored_file:read` by the global guard (Shield #2/#3); `UuidPipe` answers 400 for a
13
+ * non-uuid before any service call. Record-level decide, the tenant wall, the key-prefix and
14
+ * sha256 checks and the `file_access` audit all happen in `FilesService.open`.
15
+ * - Errors map at source: 501/503/403 come from `FilesService` with fixed messages; an engine
16
+ * deny is rethrown here as the same 403 a missing row gets (SPEC §13: same body). Never echoes
17
+ * the storage key or the name in an error.
18
+ * - Success headers: `Cache-Control: no-store` and `nosniff` via `@Header`; `Content-Type` (from
19
+ * the record), `Content-Disposition` (attachment, RFC 5987 `filename*` only) and `Content-Length`
20
+ * via `StreamableFile`, all set before the body is written. No express types needed.
21
+ */
22
+ export declare class FilesController {
23
+ private readonly files;
24
+ constructor(files: FilesService);
25
+ download(uuid: string): Promise<StreamableFile>;
26
+ }
27
+ //# sourceMappingURL=files.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.controller.d.ts","sourceRoot":"","sources":["../../../src/features/files/files.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,cAAc,EAEf,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAAE,YAAY,EAAmB,MAAM,oBAAoB,CAAC;AAQnE;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYpD;AAED;;;;;;;;;;;;GAYG;AACH,qBAEa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,YAAY;IAM1C,QAAQ,CAA0B,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAc/E"}
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.FilesController = void 0;
16
+ exports.rfc5987FileName = rfc5987FileName;
17
+ const common_1 = require("@nestjs/common");
18
+ const engine_1 = require("@astram/engine");
19
+ const guard_1 = require("@astram/guard");
20
+ const identity_error_interceptor_js_1 = require("../shared/identity-error.interceptor.js");
21
+ const files_service_js_1 = require("./files.service.js");
22
+ /** Same text as `FilesService`'s 403, so an engine deny and a missing row answer one body (§13). */
23
+ const MSG_FORBIDDEN = 'Forbidden';
24
+ /** RFC 5987 `attr-char` (RFC 8187 §3.2.1): every other UTF-8 byte is percent-encoded. */
25
+ const ATTR_CHAR = /^[A-Za-z0-9!#$&+\-.^_`|~]$/;
26
+ /**
27
+ * `filename*` value for a stored name: C0 controls and DEL dropped, the rest UTF-8 percent-encoded
28
+ * byte by byte (a lone surrogate becomes U+FFFD via `Buffer.from`, so this never throws). Quotes,
29
+ * CR, LF, `;` and spaces are always encoded, so the name cannot split or extend the header.
30
+ */
31
+ function rfc5987FileName(name) {
32
+ // eslint-disable-next-line no-control-regex
33
+ const cleaned = name.replace(/[\u0000-\u001f\u007f]/g, '');
34
+ let out = '';
35
+ for (const byte of Buffer.from(cleaned.length > 0 ? cleaned : 'download', 'utf8')) {
36
+ const ch = String.fromCharCode(byte);
37
+ out +=
38
+ byte < 0x80 && ATTR_CHAR.test(ch)
39
+ ? ch
40
+ : `%${byte.toString(16).toUpperCase().padStart(2, '0')}`;
41
+ }
42
+ return out;
43
+ }
44
+ /**
45
+ * FilesController — the framework download route `GET /files/:uuid` (file-storage SPEC §3, §5 K2).
46
+ *
47
+ * - Gated on `stored_file:read` by the global guard (Shield #2/#3); `UuidPipe` answers 400 for a
48
+ * non-uuid before any service call. Record-level decide, the tenant wall, the key-prefix and
49
+ * sha256 checks and the `file_access` audit all happen in `FilesService.open`.
50
+ * - Errors map at source: 501/503/403 come from `FilesService` with fixed messages; an engine
51
+ * deny is rethrown here as the same 403 a missing row gets (SPEC §13: same body). Never echoes
52
+ * the storage key or the name in an error.
53
+ * - Success headers: `Cache-Control: no-store` and `nosniff` via `@Header`; `Content-Type` (from
54
+ * the record), `Content-Disposition` (attachment, RFC 5987 `filename*` only) and `Content-Length`
55
+ * via `StreamableFile`, all set before the body is written. No express types needed.
56
+ */
57
+ let FilesController = class FilesController {
58
+ files;
59
+ constructor(files) {
60
+ this.files = files;
61
+ }
62
+ async download(uuid) {
63
+ let file;
64
+ try {
65
+ file = await this.files.open(uuid);
66
+ }
67
+ catch (cause) {
68
+ if (cause instanceof engine_1.AuthorizationDeniedError)
69
+ throw new common_1.ForbiddenException(MSG_FORBIDDEN);
70
+ throw cause;
71
+ }
72
+ return new common_1.StreamableFile(Buffer.from(file.bytes), {
73
+ type: file.contentType,
74
+ disposition: `attachment; filename*=UTF-8''${rfc5987FileName(file.originalName)}`,
75
+ length: file.bytes.byteLength,
76
+ });
77
+ }
78
+ };
79
+ exports.FilesController = FilesController;
80
+ __decorate([
81
+ (0, common_1.Get)(':uuid'),
82
+ (0, guard_1.Classified)({ typeKey: 'stored_file', action: 'read' }),
83
+ (0, common_1.Header)('Cache-Control', 'no-store'),
84
+ (0, common_1.Header)('X-Content-Type-Options', 'nosniff'),
85
+ __param(0, (0, common_1.Param)('uuid', guard_1.UuidPipe)),
86
+ __metadata("design:type", Function),
87
+ __metadata("design:paramtypes", [String]),
88
+ __metadata("design:returntype", Promise)
89
+ ], FilesController.prototype, "download", null);
90
+ exports.FilesController = FilesController = __decorate([
91
+ (0, common_1.Controller)('files'),
92
+ (0, common_1.UseInterceptors)(identity_error_interceptor_js_1.IdentityErrorInterceptor),
93
+ __metadata("design:paramtypes", [files_service_js_1.FilesService])
94
+ ], FilesController);
@@ -0,0 +1,87 @@
1
+ import type { AuditSink, IngestedFile, ObjectStore } from '@astram/core';
2
+ import { type RecordsService } from '@astram/engine';
3
+ /**
4
+ * The canonical content types the intake allowlist can store: today the `xlsx` profile, the only
5
+ * profile `ShieldModule` registers on `SHIELD_FILE_INGEST`. Pass the app's own list when it
6
+ * registers more profiles.
7
+ */
8
+ export declare const DEFAULT_SERVABLE_CONTENT_TYPES: readonly string[];
9
+ /** What `store()` takes: the ingest result (server-built key, sha256, canonical type) plus bytes. */
10
+ export interface StoreFileInput extends IngestedFile {
11
+ readonly bytes: Uint8Array;
12
+ }
13
+ /** What `store()` returns to the caller. Never carries the storage key (SPEC §5 I). */
14
+ export interface StoredFileSummary {
15
+ readonly uuid: string;
16
+ readonly sha256: string;
17
+ readonly sizeBytes: number;
18
+ readonly contentType: string;
19
+ readonly originalName: string;
20
+ }
21
+ /** What `open()` returns (SPEC §5 J). Never carries the storage key. */
22
+ export interface OpenedFile {
23
+ readonly bytes: Uint8Array;
24
+ readonly contentType: string;
25
+ readonly originalName: string;
26
+ readonly sizeBytes: number;
27
+ }
28
+ /**
29
+ * FilesService — stored files on the engine pipe (file-storage SPEC §5 I-K).
30
+ *
31
+ * - The `stored_file` row is written ONLY here (KI #4): the key comes from `FileIntake` (built from
32
+ * the session tenant) and is re-checked against the actor's tenant before any put or create.
33
+ * Tenant and owner are stamped by the pipe from the session (Shield #7), never sent from here.
34
+ * - Every row access goes through `RecordsService` (record gate, tenant wall, read scope, audit);
35
+ * no DB pool, no bypass flag (Shield #3, #9). The bucket is read only in `open()`, after the gate.
36
+ * - Errors map at source: 501 when no store is bound, 503 (fixed message) for store failures and
37
+ * integrity faults, 403 (fixed message) for missing, foreign or denied rows alike.
38
+ * - No actor argument (SPEC §5 I-K): the key tenant and the `file_access` audit actor come from
39
+ * `RecordsService.requestPrincipal()`, the same principal the engine stamps and gates with, so
40
+ * key tenant, row tenant/owner and audit actor cannot diverge. No principal ⇒ fail closed.
41
+ * - The engine does not audit its own denials, so a 403 from open/remove writes a `file_access`
42
+ * failure event (`denied_or_missing`, no key, no name). Logs carry the storage key only.
43
+ */
44
+ export declare class FilesService {
45
+ private readonly records;
46
+ private readonly objectStore;
47
+ private readonly audit;
48
+ private readonly logger;
49
+ private orphans;
50
+ constructor(records: RecordsService, objectStore: ObjectStore | null, audit: AuditSink, servableContentTypes?: readonly string[]);
51
+ /** Lower-cased allowlisted type -> its canonical spelling (what `open()` may serve). */
52
+ private readonly servable;
53
+ /**
54
+ * KI #13: the download Content-Type is re-checked against the intake allowlist, never taken
55
+ * from the row as-is. Anything else (a row written outside FileIntake, a profile since
56
+ * removed) is served as `application/octet-stream`.
57
+ */
58
+ private servableType;
59
+ /** Objects left behind by a failed compensating or post-commit delete since boot. */
60
+ get orphanedObjectCount(): number;
61
+ /** Put the bytes, then create the `stored_file` record; on create failure delete the object. */
62
+ store(intake: StoreFileInput): Promise<StoredFileSummary>;
63
+ /** Read a file under record-level decide, with the key and sha256 re-checked (SPEC §5 J). */
64
+ open(uuid: string): Promise<OpenedFile>;
65
+ /**
66
+ * Hard delete (team default): the record in a transaction (gated and audited by the pipe), the
67
+ * object after commit, then one `file_access` delete event (SPEC §5 K). A foreign key is never
68
+ * passed to the store.
69
+ */
70
+ remove(uuid: string): Promise<void>;
71
+ private requireStore;
72
+ /**
73
+ * Delete an object; true when the store confirmed it. On failure log the key only, count the
74
+ * orphan and answer false. Never throws.
75
+ */
76
+ private deleteObject;
77
+ /**
78
+ * A `file_access` failure event for a 403 (missing, foreign, malformed or engine-denied: one
79
+ * reason, since the caller may not learn which). Best effort; the 403 is thrown regardless.
80
+ */
81
+ private auditDenied;
82
+ /** A `file_access` failure event (best effort; the 503 is thrown regardless). */
83
+ private auditFailure;
84
+ /** `target` is the fetched row, or for a denial only the requested uuid (null if malformed). */
85
+ private event;
86
+ }
87
+ //# sourceMappingURL=files.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.service.d.ts","sourceRoot":"","sources":["../../../src/features/files/files.service.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAc,SAAS,EAAE,YAAY,EAAE,WAAW,EAAa,MAAM,cAAc,CAAC;AAEhG,OAAO,EAGL,KAAK,cAAc,EAEpB,MAAM,gBAAgB,CAAC;AAYxB;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,SAAS,MAAM,EAA8B,CAAC;AAE3F,qGAAqG;AACrG,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,uFAAuF;AACvF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,wEAAwE;AACxE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAqBD;;;;;;;;;;;;;;;GAeG;AACH,qBACa,YAAY;IAKrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK;IANxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,OAAO,CAAC,OAAO,CAAK;gBAGD,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,KAAK,EAAE,SAAS,EACjC,oBAAoB,GAAE,SAAS,MAAM,EAAmC;IAK1E,wFAAwF;IACxF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IAEvD;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAKpB,qFAAqF;IACrF,IAAI,mBAAmB,IAAI,MAAM,CAEhC;IAED,gGAAgG;IAC1F,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA4C/D,6FAA6F;IACvF,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAyD7C;;;;OAIG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCzC,OAAO,CAAC,YAAY;IAOpB;;;OAGG;YACW,YAAY;IAa1B;;;OAGG;YACW,WAAW;IAczB,iFAAiF;YACnE,YAAY;IAQ1B,gGAAgG;IAChG,OAAO,CAAC,KAAK;CAwBd"}