@spinajs/authz-queue 0.0.0-stage → 3.0.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 (102) hide show
  1. package/README.md +22 -2
  2. package/lib/cjs/api.d.ts +9 -0
  3. package/lib/cjs/api.d.ts.map +1 -0
  4. package/lib/cjs/api.js +6 -0
  5. package/lib/cjs/api.js.map +1 -0
  6. package/lib/cjs/bus/change-bus.d.ts +44 -0
  7. package/lib/cjs/bus/change-bus.d.ts.map +1 -0
  8. package/lib/cjs/bus/change-bus.js +159 -0
  9. package/lib/cjs/bus/change-bus.js.map +1 -0
  10. package/lib/cjs/bus/index.d.ts +3 -0
  11. package/lib/cjs/bus/index.d.ts.map +1 -0
  12. package/lib/cjs/bus/index.js +19 -0
  13. package/lib/cjs/bus/index.js.map +1 -0
  14. package/lib/cjs/bus/route-source.d.ts +11 -0
  15. package/lib/cjs/bus/route-source.d.ts.map +1 -0
  16. package/lib/cjs/bus/route-source.js +32 -0
  17. package/lib/cjs/bus/route-source.js.map +1 -0
  18. package/lib/cjs/hook/hook.d.ts +21 -0
  19. package/lib/cjs/hook/hook.d.ts.map +1 -0
  20. package/lib/cjs/hook/hook.js +81 -0
  21. package/lib/cjs/hook/hook.js.map +1 -0
  22. package/lib/cjs/hook/index.d.ts +3 -0
  23. package/lib/cjs/hook/index.d.ts.map +1 -0
  24. package/lib/cjs/hook/index.js +19 -0
  25. package/lib/cjs/hook/index.js.map +1 -0
  26. package/lib/cjs/hook/initiator.d.ts +28 -0
  27. package/lib/cjs/hook/initiator.d.ts.map +1 -0
  28. package/lib/cjs/hook/initiator.js +128 -0
  29. package/lib/cjs/hook/initiator.js.map +1 -0
  30. package/lib/cjs/index.d.ts +5 -0
  31. package/lib/cjs/index.d.ts.map +1 -0
  32. package/lib/cjs/index.js +21 -0
  33. package/lib/cjs/index.js.map +1 -0
  34. package/lib/cjs/job/index.d.ts +2 -0
  35. package/lib/cjs/job/index.d.ts.map +1 -0
  36. package/lib/cjs/job/index.js +18 -0
  37. package/lib/cjs/job/index.js.map +1 -0
  38. package/lib/cjs/job/job-grant.d.ts +12 -0
  39. package/lib/cjs/job/job-grant.d.ts.map +1 -0
  40. package/lib/cjs/job/job-grant.js +29 -0
  41. package/lib/cjs/job/job-grant.js.map +1 -0
  42. package/lib/cjs/job/job-resource.d.ts +10 -0
  43. package/lib/cjs/job/job-resource.d.ts.map +1 -0
  44. package/lib/cjs/job/job-resource.js +39 -0
  45. package/lib/cjs/job/job-resource.js.map +1 -0
  46. package/lib/cjs/package.json +1 -0
  47. package/lib/cjs/schema.d.ts +34 -0
  48. package/lib/cjs/schema.d.ts.map +1 -0
  49. package/lib/cjs/schema.js +45 -0
  50. package/lib/cjs/schema.js.map +1 -0
  51. package/lib/mjs/api.d.ts +9 -0
  52. package/lib/mjs/api.d.ts.map +1 -0
  53. package/lib/mjs/api.js +2 -0
  54. package/lib/mjs/api.js.map +1 -0
  55. package/lib/mjs/bus/change-bus.d.ts +44 -0
  56. package/lib/mjs/bus/change-bus.d.ts.map +1 -0
  57. package/lib/mjs/bus/change-bus.js +155 -0
  58. package/lib/mjs/bus/change-bus.js.map +1 -0
  59. package/lib/mjs/bus/index.d.ts +3 -0
  60. package/lib/mjs/bus/index.d.ts.map +1 -0
  61. package/lib/mjs/bus/index.js +3 -0
  62. package/lib/mjs/bus/index.js.map +1 -0
  63. package/lib/mjs/bus/route-source.d.ts +11 -0
  64. package/lib/mjs/bus/route-source.d.ts.map +1 -0
  65. package/lib/mjs/bus/route-source.js +29 -0
  66. package/lib/mjs/bus/route-source.js.map +1 -0
  67. package/lib/mjs/hook/hook.d.ts +21 -0
  68. package/lib/mjs/hook/hook.d.ts.map +1 -0
  69. package/lib/mjs/hook/hook.js +78 -0
  70. package/lib/mjs/hook/hook.js.map +1 -0
  71. package/lib/mjs/hook/index.d.ts +3 -0
  72. package/lib/mjs/hook/index.d.ts.map +1 -0
  73. package/lib/mjs/hook/index.js +3 -0
  74. package/lib/mjs/hook/index.js.map +1 -0
  75. package/lib/mjs/hook/initiator.d.ts +28 -0
  76. package/lib/mjs/hook/initiator.d.ts.map +1 -0
  77. package/lib/mjs/hook/initiator.js +123 -0
  78. package/lib/mjs/hook/initiator.js.map +1 -0
  79. package/lib/mjs/index.d.ts +5 -0
  80. package/lib/mjs/index.d.ts.map +1 -0
  81. package/lib/mjs/index.js +5 -0
  82. package/lib/mjs/index.js.map +1 -0
  83. package/lib/mjs/job/index.d.ts +2 -0
  84. package/lib/mjs/job/index.d.ts.map +1 -0
  85. package/lib/mjs/job/index.js +2 -0
  86. package/lib/mjs/job/index.js.map +1 -0
  87. package/lib/mjs/job/job-grant.d.ts +12 -0
  88. package/lib/mjs/job/job-grant.d.ts.map +1 -0
  89. package/lib/mjs/job/job-grant.js +26 -0
  90. package/lib/mjs/job/job-grant.js.map +1 -0
  91. package/lib/mjs/job/job-resource.d.ts +10 -0
  92. package/lib/mjs/job/job-resource.d.ts.map +1 -0
  93. package/lib/mjs/job/job-resource.js +36 -0
  94. package/lib/mjs/job/job-resource.js.map +1 -0
  95. package/lib/mjs/package.json +1 -0
  96. package/lib/mjs/schema.d.ts +34 -0
  97. package/lib/mjs/schema.d.ts.map +1 -0
  98. package/lib/mjs/schema.js +42 -0
  99. package/lib/mjs/schema.js.map +1 -0
  100. package/lib/tsconfig.cjs.tsbuildinfo +1 -0
  101. package/lib/tsconfig.mjs.tsbuildinfo +1 -0
  102. package/package.json +87 -4
@@ -0,0 +1,128 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.StampedInitiatorPrincipalFactory = exports.InitiatorPrincipalFactory = void 0;
13
+ exports.reviveCeiling = reviveCeiling;
14
+ const di_1 = require("@spinajs/di");
15
+ const configuration_1 = require("@spinajs/configuration");
16
+ const authz_1 = require("@spinajs/authz");
17
+ const util_1 = require("@spinajs/util");
18
+ /**
19
+ * Builds the principal a job runs as from the `Initiator` on its message. An app that must reload
20
+ * the user (attributes, deactivation) registers its own with `DI.register(X).as(InitiatorPrincipalFactory)`.
21
+ * Return `UNATTENDED` for an initiator that can no longer act; throw only for a failure worth a retry.
22
+ */
23
+ class InitiatorPrincipalFactory {
24
+ }
25
+ exports.InitiatorPrincipalFactory = InitiatorPrincipalFactory;
26
+ // null counts as absent, as in the engine's ceiling reader.
27
+ function reviveDate(v) {
28
+ const d = v instanceof Date ? v : typeof v === 'string' || typeof v === 'number' ? new Date(v) : undefined;
29
+ return d !== undefined && !Number.isNaN(d.getTime()) ? d : undefined;
30
+ }
31
+ /** Rebuilds a Ceiling that went through a JSON broker (`expiresAt` is a string there); undefined when the shape is wrong. */
32
+ function reviveCeiling(raw) {
33
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
34
+ return undefined;
35
+ const c = Object.fromEntries(Object.entries(raw).filter(([, v]) => v !== null));
36
+ const out = {};
37
+ if (c.roles !== undefined) {
38
+ if (!(0, util_1.isStringArray)(c.roles))
39
+ return undefined;
40
+ out.roles = [...c.roles];
41
+ }
42
+ if (c.permissions !== undefined) {
43
+ if (!(0, util_1.isStringArray)(c.permissions))
44
+ return undefined;
45
+ out.permissions = [...c.permissions];
46
+ }
47
+ if (c.resources !== undefined) {
48
+ if (!Array.isArray(c.resources))
49
+ return undefined;
50
+ const resources = [];
51
+ for (const r of c.resources) {
52
+ if (r === null || typeof r !== 'object')
53
+ return undefined;
54
+ const { type, id } = r;
55
+ if (typeof type !== 'string' || (id !== undefined && typeof id !== 'string'))
56
+ return undefined;
57
+ resources.push(id === undefined ? { type } : { type, id });
58
+ }
59
+ out.resources = resources;
60
+ }
61
+ if (c.expiresAt !== undefined) {
62
+ const expiresAt = reviveDate(c.expiresAt);
63
+ if (expiresAt === undefined)
64
+ return undefined;
65
+ out.expiresAt = expiresAt;
66
+ }
67
+ if (c.reason !== undefined) {
68
+ if (typeof c.reason !== 'string')
69
+ return undefined;
70
+ out.reason = c.reason;
71
+ }
72
+ return out;
73
+ }
74
+ /** Trusts the stamp: type, id and ceiling are all the principal has. A malformed stamp yields `UNATTENDED`. */
75
+ let StampedInitiatorPrincipalFactory = class StampedInitiatorPrincipalFactory extends InitiatorPrincipalFactory {
76
+ /**
77
+ * `warn` decides the one-time warning without reading the config, for a wrapper built with `new` that does reload the user.
78
+ * Without it, `authz.queue.stampedInitiatorWarning` decides, so a `new` instance needs a resolved Configuration.
79
+ */
80
+ constructor(options = {}) {
81
+ super();
82
+ this.warned = false;
83
+ this.Log = (0, authz_1.engineLog)('authz-queue');
84
+ this.warn = options.warn;
85
+ }
86
+ async principalOf(initiator) {
87
+ if (!this.warned) {
88
+ // The schema default keeps the warning; so does a value the schema never saw.
89
+ const warn = this.warn ?? this.WarningSwitch !== false;
90
+ this.warned = true;
91
+ if (warn)
92
+ this.Log.warn('authz-queue: jobs run as their initiator from the stamp alone; register an InitiatorPrincipalFactory that reloads the user so deactivated users stop acting');
93
+ }
94
+ if (initiator === null || typeof initiator !== 'object')
95
+ return authz_1.UNATTENDED;
96
+ const { type, id, ceiling } = initiator;
97
+ if (typeof type !== 'string' || type === '' || typeof id !== 'string' || id === '')
98
+ return authz_1.UNATTENDED;
99
+ if (type === 'system')
100
+ return authz_1.SYSTEM;
101
+ if (type === 'unattended')
102
+ return authz_1.UNATTENDED;
103
+ let revived;
104
+ if (ceiling !== undefined && ceiling !== null) {
105
+ revived = reviveCeiling(ceiling);
106
+ if (revived === undefined)
107
+ return authz_1.UNATTENDED;
108
+ }
109
+ return Object.freeze({
110
+ type,
111
+ id,
112
+ authenticated: type !== 'anonymous',
113
+ source: 'queue',
114
+ attributes: Object.freeze({}),
115
+ ...(revived ? { ceiling: revived } : {}),
116
+ });
117
+ }
118
+ };
119
+ exports.StampedInitiatorPrincipalFactory = StampedInitiatorPrincipalFactory;
120
+ __decorate([
121
+ (0, configuration_1.Config)('authz.queue.stampedInitiatorWarning'),
122
+ __metadata("design:type", Boolean)
123
+ ], StampedInitiatorPrincipalFactory.prototype, "WarningSwitch", void 0);
124
+ exports.StampedInitiatorPrincipalFactory = StampedInitiatorPrincipalFactory = __decorate([
125
+ (0, di_1.Injectable)(InitiatorPrincipalFactory),
126
+ __metadata("design:paramtypes", [Object])
127
+ ], StampedInitiatorPrincipalFactory);
128
+ //# sourceMappingURL=initiator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initiator.js","sourceRoot":"","sources":["../../../src/hook/initiator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export * from './api.js';
2
+ export * from './hook/index.js';
3
+ export * from './bus/index.js';
4
+ export * from './schema.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./api.js"), exports);
18
+ __exportStar(require("./hook/index.js"), exports);
19
+ __exportStar(require("./bus/index.js"), exports);
20
+ __exportStar(require("./schema.js"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,kDAAgC;AAChC,iDAA+B;AAC/B,8CAA4B"}
@@ -0,0 +1,2 @@
1
+ export * from './job-resource.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/job/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./job-resource.js"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/job/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAkC"}
@@ -0,0 +1,12 @@
1
+ import { ConfigurationSource } from '@spinajs/configuration';
2
+ import type { IConfigLike } from '@spinajs/configuration';
3
+ /**
4
+ * Every user holds job:read on the jobs they emitted (the `owner` relation is the job's initiator). It is a source and not a
5
+ * config file because every installed package's config dir is read whether or not the package is imported, and a
6
+ * grant of a permission nothing registered fails the boot. Order 0 loads before the file sources.
7
+ */
8
+ export declare class JobGrantSource extends ConfigurationSource {
9
+ get Order(): number;
10
+ Load(): Promise<IConfigLike>;
11
+ }
12
+ //# sourceMappingURL=job-grant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-grant.d.ts","sourceRoot":"","sources":["../../../src/job/job-grant.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;GAIG;AACH,qBACa,cAAe,SAAQ,mBAAmB;IACrD,IAAW,KAAK,IAAI,MAAM,CAEzB;IAEM,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC,CAElC;CACF"}
@@ -0,0 +1,29 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.JobGrantSource = void 0;
10
+ const di_1 = require("@spinajs/di");
11
+ const configuration_1 = require("@spinajs/configuration");
12
+ /**
13
+ * Every user holds job:read on the jobs they emitted (the `owner` relation is the job's initiator). It is a source and not a
14
+ * config file because every installed package's config dir is read whether or not the package is imported, and a
15
+ * grant of a permission nothing registered fails the boot. Order 0 loads before the file sources.
16
+ */
17
+ let JobGrantSource = class JobGrantSource extends configuration_1.ConfigurationSource {
18
+ get Order() {
19
+ return 0;
20
+ }
21
+ Load() {
22
+ return Promise.resolve({ authz: { rbac: { roles: { user: { grants: [{ permission: 'job:read', relation: 'owner' }] } } } } });
23
+ }
24
+ };
25
+ exports.JobGrantSource = JobGrantSource;
26
+ exports.JobGrantSource = JobGrantSource = __decorate([
27
+ (0, di_1.Injectable)(configuration_1.ConfigurationSource)
28
+ ], JobGrantSource);
29
+ //# sourceMappingURL=job-grant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-grant.js","sourceRoot":"","sources":["../../../src/job/job-grant.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oCAAyC;AACzC,0DAA6D;AAG7D;;;;GAIG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,mCAAmB;IACrD,IAAW,KAAK;QACd,OAAO,CAAC,CAAC;IACX,CAAC;IAEM,IAAI;QACT,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAA4B,CAAC,CAAC;IAC1J,CAAC;CACF,CAAA;;yBARY,cAAc;IAD1B,IAAA,eAAU,EAAC,mCAAmB,CAAC;GACnB,cAAc,CAQ1B"}
@@ -0,0 +1,10 @@
1
+ import { AuthzDomains } from '@spinajs/authz';
2
+ import { QueueTrackingHook } from '@spinajs/queue';
3
+ import './job-grant.js';
4
+ /** The queue's own job-row queries run as SYSTEM: the job's principal may not touch the table. */
5
+ export declare class AuthzQueueTrackingHook extends QueueTrackingHook {
6
+ protected Domain: string;
7
+ protected Domains: AuthzDomains;
8
+ aroundTracking<T>(next: () => Promise<T>): Promise<T>;
9
+ }
10
+ //# sourceMappingURL=job-resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-resource.d.ts","sourceRoot":"","sources":["../../../src/job/job-resource.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAU,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAY,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,gBAAgB,CAAC;AAKxB,kGAAkG;AAClG,qBACa,sBAAuB,SAAQ,iBAAiB;IAE3D,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IAGzB,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC;IAE1B,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAE1D;CACF"}
@@ -0,0 +1,39 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AuthzQueueTrackingHook = void 0;
13
+ const di_1 = require("@spinajs/di");
14
+ const configuration_1 = require("@spinajs/configuration");
15
+ const authz_orm_1 = require("@spinajs/authz-orm");
16
+ const authz_1 = require("@spinajs/authz");
17
+ const queue_1 = require("@spinajs/queue");
18
+ require("./job-grant.js");
19
+ // The initiator may be any principal type, so the owner relation compares the type column too.
20
+ (0, authz_orm_1.registerAccessResource)(queue_1.JobModel, 'job', { owner: { column: 'InitiatorId', typeColumn: 'InitiatorType' } });
21
+ /** The queue's own job-row queries run as SYSTEM: the job's principal may not touch the table. */
22
+ let AuthzQueueTrackingHook = class AuthzQueueTrackingHook extends queue_1.QueueTrackingHook {
23
+ async aroundTracking(next) {
24
+ return (await this.Domains.service(this.Domain)).runAs(authz_1.SYSTEM, 'queue:tracking', next);
25
+ }
26
+ };
27
+ exports.AuthzQueueTrackingHook = AuthzQueueTrackingHook;
28
+ __decorate([
29
+ (0, configuration_1.Config)('authz.queue.domain'),
30
+ __metadata("design:type", String)
31
+ ], AuthzQueueTrackingHook.prototype, "Domain", void 0);
32
+ __decorate([
33
+ (0, di_1.Autoinject)(authz_1.AuthzDomains),
34
+ __metadata("design:type", authz_1.AuthzDomains)
35
+ ], AuthzQueueTrackingHook.prototype, "Domains", void 0);
36
+ exports.AuthzQueueTrackingHook = AuthzQueueTrackingHook = __decorate([
37
+ (0, di_1.Injectable)(queue_1.QueueTrackingHook)
38
+ ], AuthzQueueTrackingHook);
39
+ //# sourceMappingURL=job-resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-resource.js","sourceRoot":"","sources":["../../../src/job/job-resource.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oCAAqD;AACrD,0DAAgD;AAChD,kDAA4D;AAC5D,0CAAsD;AACtD,0CAA6D;AAE7D,0BAAwB;AAExB,+FAA+F;AAC/F,IAAA,kCAAsB,EAAC,gBAAQ,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC;AAE3G,kGAAkG;AAE3F,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,yBAAiB;IAO3D,KAAK,CAAC,cAAc,CAAI,IAAsB;QAC5C,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,cAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;IACzF,CAAC;CACF,CAAA;;AARW;IADT,IAAA,sBAAM,EAAC,oBAAoB,CAAC;;sDACJ;AAGf;IADT,IAAA,eAAU,EAAC,oBAAY,CAAC;8BACN,oBAAY;uDAAC;iCALrB,sBAAsB;IADlC,IAAA,eAAU,EAAC,yBAAiB,CAAC;GACjB,sBAAsB,CAUlC"}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,34 @@
1
+ import { Bootstrapper } from '@spinajs/di';
2
+ export declare const AUTHZ_QUEUE_CONFIGURATION_SCHEMA: {
3
+ $id: string;
4
+ $configurationModule: string;
5
+ description: string;
6
+ type: string;
7
+ properties: {
8
+ domain: {
9
+ type: string;
10
+ minLength: number;
11
+ default: string;
12
+ };
13
+ stampedInitiatorWarning: {
14
+ type: string;
15
+ default: boolean;
16
+ };
17
+ };
18
+ };
19
+ export declare const AUTHZ_BUS_TOPIC_CONFIGURATION_SCHEMA: {
20
+ $id: string;
21
+ $configurationModule: string;
22
+ description: string;
23
+ type: string;
24
+ properties: {
25
+ topic: {
26
+ type: string;
27
+ minLength: number;
28
+ };
29
+ };
30
+ };
31
+ export declare class AuthzQueueConfigBootstrapper extends Bootstrapper {
32
+ bootstrap(): void;
33
+ }
34
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAIvD,eAAO,MAAM,gCAAgC;;;;;;;;;;;;YASd,IAAI;YAAa,OAAO;;;CAEtD,CAAC;AAGF,eAAO,MAAM,oCAAoC;IAC/C,GAAG;IACH,oBAAoB;IACpB,WAAW;IACX,IAAI;IACJ,UAAU;QAAI,KAAK;;;;;CACpB,CAAC;AAKF,qBACa,4BAA6B,SAAQ,YAAY;IACrD,SAAS,IAAI,IAAI,CAGvB;CACF"}
@@ -0,0 +1,45 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.AuthzQueueConfigBootstrapper = exports.AUTHZ_BUS_TOPIC_CONFIGURATION_SCHEMA = exports.AUTHZ_QUEUE_CONFIGURATION_SCHEMA = void 0;
10
+ const configuration_1 = require("@spinajs/configuration");
11
+ const di_1 = require("@spinajs/di");
12
+ const name = { type: 'string', minLength: 1 };
13
+ exports.AUTHZ_QUEUE_CONFIGURATION_SCHEMA = {
14
+ $id: 'spinajs/authz-queue.configuration.schema.json',
15
+ $configurationModule: 'authz.queue',
16
+ description: 'Queue authorization configuration (authz.queue.*)',
17
+ type: 'object',
18
+ properties: {
19
+ // The authz domain whose principal a message carries and whose runAs its handler uses.
20
+ domain: { ...name, default: 'root' },
21
+ // Whether StampedInitiatorPrincipalFactory warns, once, that jobs run from the stamp alone; false for an app that accepts that.
22
+ stampedInitiatorWarning: { type: 'boolean', default: true },
23
+ },
24
+ };
25
+ // authz.bus belongs to the core schema, which leaves it open; the topic is the queue bus's own key.
26
+ exports.AUTHZ_BUS_TOPIC_CONFIGURATION_SCHEMA = {
27
+ $id: 'spinajs/authz-queue-bus.configuration.schema.json',
28
+ $configurationModule: 'authz.bus',
29
+ description: 'Queue change bus configuration (authz.bus.topic)',
30
+ type: 'object',
31
+ properties: { topic: name },
32
+ };
33
+ (0, configuration_1.registerConfigurationSchemaAtImport)(exports.AUTHZ_QUEUE_CONFIGURATION_SCHEMA);
34
+ (0, configuration_1.registerConfigurationSchemaAtImport)(exports.AUTHZ_BUS_TOPIC_CONFIGURATION_SCHEMA);
35
+ let AuthzQueueConfigBootstrapper = class AuthzQueueConfigBootstrapper extends di_1.Bootstrapper {
36
+ bootstrap() {
37
+ (0, configuration_1.registerConfigurationSchema)(exports.AUTHZ_QUEUE_CONFIGURATION_SCHEMA);
38
+ (0, configuration_1.registerConfigurationSchema)(exports.AUTHZ_BUS_TOPIC_CONFIGURATION_SCHEMA);
39
+ }
40
+ };
41
+ exports.AuthzQueueConfigBootstrapper = AuthzQueueConfigBootstrapper;
42
+ exports.AuthzQueueConfigBootstrapper = AuthzQueueConfigBootstrapper = __decorate([
43
+ (0, di_1.Injectable)(di_1.Bootstrapper)
44
+ ], AuthzQueueConfigBootstrapper);
45
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":";;;;;;;;;AAAA,0DAA0G;AAC1G,oCAAuD;AAEvD,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;AAEjC,QAAA,gCAAgC,GAAG;IAC9C,GAAG,EAAE,+CAA+C;IACpD,oBAAoB,EAAE,aAAa;IACnC,WAAW,EAAE,mDAAmD;IAChE,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,uFAAuF;QACvF,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE;QACpC,gIAAgI;QAChI,uBAAuB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE;KAC5D;CACF,CAAC;AAEF,oGAAoG;AACvF,QAAA,oCAAoC,GAAG;IAClD,GAAG,EAAE,mDAAmD;IACxD,oBAAoB,EAAE,WAAW;IACjC,WAAW,EAAE,kDAAkD;IAC/D,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;CAC5B,CAAC;AAEF,IAAA,mDAAmC,EAAC,QAAA,gCAAgC,CAAC,CAAC;AACtE,IAAA,mDAAmC,EAAC,QAAA,oCAAoC,CAAC,CAAC;AAGnE,IAAM,4BAA4B,GAAlC,MAAM,4BAA6B,SAAQ,iBAAY;IACrD,SAAS;QACd,IAAA,2CAA2B,EAAC,QAAA,gCAAgC,CAAC,CAAC;QAC9D,IAAA,2CAA2B,EAAC,QAAA,oCAAoC,CAAC,CAAC;IACpE,CAAC;CACF,CAAA;;uCALY,4BAA4B;IADxC,IAAA,eAAU,EAAC,iBAAY,CAAC;GACZ,4BAA4B,CAKxC"}
@@ -0,0 +1,9 @@
1
+ import type { Ceiling, PrincipalType } from '@spinajs/authz';
2
+ export { QueueMessageHook } from '@spinajs/queue';
3
+ export type { JobOptions } from '@spinajs/queue';
4
+ export interface Initiator {
5
+ readonly type: PrincipalType;
6
+ readonly id: string;
7
+ readonly ceiling?: Ceiling;
8
+ }
9
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B"}
package/lib/mjs/api.js ADDED
@@ -0,0 +1,2 @@
1
+ export { QueueMessageHook } from '@spinajs/queue';
2
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { ChangeBus } from '@spinajs/authz';
2
+ import type { AuthzChange } from '@spinajs/authz';
3
+ import { QueueEvent, QueueService } from '@spinajs/queue';
4
+ interface WireChange {
5
+ domain?: unknown;
6
+ tags?: unknown;
7
+ actor?: unknown;
8
+ at?: unknown;
9
+ }
10
+ /** What nodes send each other: the change, and the node that made it so that it can skip its own echo. */
11
+ export declare class AuthzChangeEvent extends QueueEvent {
12
+ Node: string;
13
+ Change: WireChange;
14
+ }
15
+ /** Rebuilds a change that went through a JSON broker; undefined when it cannot be one. */
16
+ export declare function reviveChange(raw: unknown): AuthzChange | undefined;
17
+ /**
18
+ * A ChangeBus that carries changes to the other nodes over the queue (design §14.2).
19
+ * Select it with `authz.bus.service: 'QueueChangeBus'`. Subscribers on this node hear a change at once;
20
+ * the copy that comes back from the broker is skipped.
21
+ */
22
+ export declare class QueueChangeBus extends ChangeBus {
23
+ protected readonly node: `${string}-${string}-${string}-${string}-${string}`;
24
+ private readonly subscribers;
25
+ private readonly log;
26
+ private queue?;
27
+ private retried;
28
+ private disposed;
29
+ private timer?;
30
+ protected retryMs: number;
31
+ publish(change: AuthzChange): Promise<void>;
32
+ subscribe(fn: (c: AuthzChange) => void): () => void;
33
+ /** AuthzService subscribes once, at boot: a queue that is not ready yet must not leave the node deaf. */
34
+ private listenWithRetry;
35
+ dispose(): Promise<void>;
36
+ /** Resolved per start, not injected: a queue that cannot start yet must not fail the bus, which retries. */
37
+ protected queueService(): Promise<QueueService>;
38
+ protected start(): Promise<QueueService>;
39
+ private listen;
40
+ private deliver;
41
+ private fail;
42
+ }
43
+ export {};
44
+ //# sourceMappingURL=change-bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-bus.d.ts","sourceRoot":"","sources":["../../../src/bus/change-bus.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAA0B,MAAM,gBAAgB,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAS,UAAU,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGjE,UAAU,UAAU;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,EAAE,CAAC,EAAE,OAAO,CAAC;CACd;AAED,0GAA0G;AAC1G,qBACa,gBAAiB,SAAQ,UAAU;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;CAC3B;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,GAAG,SAAS,CAoBlE;AAED;;;;GAIG;AACH,qBAEa,cAAe,SAAQ,SAAS;IAC3C,SAAS,CAAC,QAAQ,CAAC,IAAI,sDAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuC;IACnE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgC;IACpD,OAAO,CAAC,KAAK,CAAC,CAAwB;IACtC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAC,CAAiB;IAC/B,SAAS,CAAC,OAAO,SAAQ;IAEnB,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhD;IAED,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI,CAOlD;IAED,yGAAyG;IACzG,OAAO,CAAC,eAAe;IAsBjB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ7B;IAED,4GAA4G;IAC5G,UAAgB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,CAEpD;IAED,SAAS,CAAC,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC,CASvC;YAEa,MAAM;IAcpB,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,IAAI;CAGb"}
@@ -0,0 +1,155 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { randomUUID } from 'node:crypto';
8
+ import { DI, Injectable, Singleton } from '@spinajs/di';
9
+ import { ChangeBus, engineLog, thrownError } from '@spinajs/authz';
10
+ import { Event, QueueEvent, QueueService } from '@spinajs/queue';
11
+ import { isStringArray } from '@spinajs/util';
12
+ /** What nodes send each other: the change, and the node that made it so that it can skip its own echo. */
13
+ let AuthzChangeEvent = class AuthzChangeEvent extends QueueEvent {
14
+ };
15
+ AuthzChangeEvent = __decorate([
16
+ Event()
17
+ ], AuthzChangeEvent);
18
+ export { AuthzChangeEvent };
19
+ /** Rebuilds a change that went through a JSON broker; undefined when it cannot be one. */
20
+ export function reviveChange(raw) {
21
+ if (raw === null || typeof raw !== 'object')
22
+ return undefined;
23
+ const c = raw;
24
+ if (!isStringArray(c.tags))
25
+ return undefined;
26
+ if (c.domain !== undefined && typeof c.domain !== 'string')
27
+ return undefined;
28
+ let actor;
29
+ if (c.actor !== undefined) {
30
+ const a = c.actor;
31
+ if (a === null || typeof a !== 'object' || typeof a.type !== 'string' || typeof a.id !== 'string')
32
+ return undefined;
33
+ actor = { type: a.type, id: a.id };
34
+ }
35
+ const at = new Date(typeof c.at === 'string' || typeof c.at === 'number' || c.at instanceof Date ? c.at : NaN);
36
+ return {
37
+ ...(c.domain === undefined ? {} : { domain: c.domain }),
38
+ tags: [...c.tags],
39
+ ...(actor ? { actor } : {}),
40
+ at: Number.isNaN(at.getTime()) ? new Date() : at,
41
+ };
42
+ }
43
+ /**
44
+ * A ChangeBus that carries changes to the other nodes over the queue (design §14.2).
45
+ * Select it with `authz.bus.service: 'QueueChangeBus'`. Subscribers on this node hear a change at once;
46
+ * the copy that comes back from the broker is skipped.
47
+ */
48
+ let QueueChangeBus = class QueueChangeBus extends ChangeBus {
49
+ constructor() {
50
+ super(...arguments);
51
+ this.node = randomUUID();
52
+ this.subscribers = new Set();
53
+ this.log = engineLog('authz-queue-bus');
54
+ this.retried = false;
55
+ this.disposed = false;
56
+ this.retryMs = 5000;
57
+ }
58
+ async publish(change) {
59
+ this.deliver(change);
60
+ const queue = await this.start();
61
+ const event = new AuthzChangeEvent();
62
+ event.Node = this.node;
63
+ event.Change = { domain: change.domain, tags: [...change.tags], actor: change.actor, at: change.at };
64
+ await queue.emit(event);
65
+ }
66
+ subscribe(fn) {
67
+ const entry = (c) => fn(c);
68
+ this.subscribers.add(entry);
69
+ this.listenWithRetry();
70
+ return () => {
71
+ this.subscribers.delete(entry);
72
+ };
73
+ }
74
+ /** AuthzService subscribes once, at boot: a queue that is not ready yet must not leave the node deaf. */
75
+ listenWithRetry() {
76
+ this.start().then(() => {
77
+ // Changes made while the node was deaf are unknown: drop everything.
78
+ if (this.retried) {
79
+ this.retried = false;
80
+ this.deliver({ tags: ['*'], at: new Date() });
81
+ }
82
+ }, (err) => {
83
+ this.log.error({ error: thrownError(err) }, 'authz change bus: cannot listen on the queue, retrying');
84
+ this.retried = true;
85
+ if (this.disposed || this.timer)
86
+ return;
87
+ this.timer = setTimeout(() => {
88
+ this.timer = undefined;
89
+ if (!this.disposed)
90
+ this.listenWithRetry();
91
+ }, this.retryMs);
92
+ this.timer.unref?.();
93
+ });
94
+ }
95
+ async dispose() {
96
+ this.disposed = true;
97
+ if (this.timer)
98
+ clearTimeout(this.timer);
99
+ this.timer = undefined;
100
+ this.subscribers.clear();
101
+ const started = this.queue;
102
+ this.queue = undefined;
103
+ if (started)
104
+ await (await started.catch(() => undefined))?.stopConsuming(AuthzChangeEvent);
105
+ }
106
+ /** Resolved per start, not injected: a queue that cannot start yet must not fail the bus, which retries. */
107
+ async queueService() {
108
+ return DI.resolve(QueueService);
109
+ }
110
+ start() {
111
+ if (this.queue === undefined) {
112
+ this.queue = this.listen();
113
+ // A failed start is retried by the next call.
114
+ this.queue.catch(() => {
115
+ this.queue = undefined;
116
+ });
117
+ }
118
+ return this.queue;
119
+ }
120
+ async listen() {
121
+ const queue = await this.queueService();
122
+ await queue.consume(AuthzChangeEvent, async (e) => {
123
+ if (e.Node === this.node)
124
+ return;
125
+ const change = reviveChange(e.Change);
126
+ if (change === undefined) {
127
+ this.log.warn('authz change bus: dropped a malformed change');
128
+ return;
129
+ }
130
+ this.deliver(change);
131
+ });
132
+ return queue;
133
+ }
134
+ deliver(change) {
135
+ for (const fn of [...this.subscribers]) {
136
+ try {
137
+ const r = fn(change);
138
+ if (r !== null && typeof r === 'object' && typeof r.then === 'function')
139
+ r.then(undefined, (err) => this.fail(err));
140
+ }
141
+ catch (err) {
142
+ this.fail(err);
143
+ }
144
+ }
145
+ }
146
+ fail(err) {
147
+ this.log.error({ error: thrownError(err) }, 'authz change subscriber failed');
148
+ }
149
+ };
150
+ QueueChangeBus = __decorate([
151
+ Singleton(),
152
+ Injectable(ChangeBus)
153
+ ], QueueChangeBus);
154
+ export { QueueChangeBus };
155
+ //# sourceMappingURL=change-bus.js.map