n8n 2.45.1 → 2.45.2

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 (44) hide show
  1. package/dist/build.tsbuildinfo +1 -1
  2. package/dist/commands/base-command.d.ts +2 -0
  3. package/dist/commands/base-command.js +35 -1
  4. package/dist/commands/base-command.js.map +1 -1
  5. package/dist/load-nodes-and-credentials.d.ts +1 -0
  6. package/dist/load-nodes-and-credentials.js +8 -2
  7. package/dist/load-nodes-and-credentials.js.map +1 -1
  8. package/dist/modules/agents/agents.service.js +10 -5
  9. package/dist/modules/agents/agents.service.js.map +1 -1
  10. package/dist/modules/agents/builder/get-resource-locator-options.tool.d.ts +2 -2
  11. package/dist/modules/agents/repositories/agent.repository.d.ts +5 -0
  12. package/dist/modules/agents/repositories/agent.repository.js +48 -10
  13. package/dist/modules/agents/repositories/agent.repository.js.map +1 -1
  14. package/dist/modules/agents/utils/agent-ref.d.ts +3 -1
  15. package/dist/modules/agents/utils/agent-ref.js +3 -2
  16. package/dist/modules/agents/utils/agent-ref.js.map +1 -1
  17. package/dist/modules/breaking-changes/breaking-changes.controller.d.ts +1 -0
  18. package/dist/modules/breaking-changes/breaking-changes.controller.js +19 -0
  19. package/dist/modules/breaking-changes/breaking-changes.controller.js.map +1 -1
  20. package/dist/modules/breaking-changes/migration-report-csv.d.ts +3 -0
  21. package/dist/modules/breaking-changes/migration-report-csv.js +66 -0
  22. package/dist/modules/breaking-changes/migration-report-csv.js.map +1 -0
  23. package/dist/modules/type-availability-policies/database/repositories/type-availability-policy-scope.repository.d.ts +8 -2
  24. package/dist/modules/type-availability-policies/database/repositories/type-availability-policy-scope.repository.js +15 -11
  25. package/dist/modules/type-availability-policies/database/repositories/type-availability-policy-scope.repository.js.map +1 -1
  26. package/dist/modules/type-availability-policies/effective-policy.d.ts +17 -0
  27. package/dist/modules/type-availability-policies/effective-policy.js +33 -0
  28. package/dist/modules/type-availability-policies/effective-policy.js.map +1 -0
  29. package/dist/modules/type-availability-policies/policy-rule.types.d.ts +0 -4
  30. package/dist/modules/type-availability-policies/type-availability-policies.module.js +2 -0
  31. package/dist/modules/type-availability-policies/type-availability-policies.module.js.map +1 -1
  32. package/dist/modules/type-availability-policies/type-availability-policy-snapshot.d.ts +28 -0
  33. package/dist/modules/type-availability-policies/type-availability-policy-snapshot.js +138 -0
  34. package/dist/modules/type-availability-policies/type-availability-policy-snapshot.js.map +1 -0
  35. package/dist/modules/type-availability-policies/type-availability-policy.service.d.ts +8 -25
  36. package/dist/modules/type-availability-policies/type-availability-policy.service.js +42 -171
  37. package/dist/modules/type-availability-policies/type-availability-policy.service.js.map +1 -1
  38. package/dist/scaling/constants.d.ts +2 -2
  39. package/dist/scaling/pubsub/pubsub.event-map.d.ts +5 -1
  40. package/dist/scaling/pubsub/pubsub.types.d.ts +2 -1
  41. package/dist/scaling/pubsub/subscriber.service.js +2 -0
  42. package/dist/scaling/pubsub/subscriber.service.js.map +1 -1
  43. package/dist/user-management/email/templates/n8n-logo.png +0 -0
  44. package/package.json +36 -36
@@ -0,0 +1,138 @@
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.TypeAvailabilityPolicySnapshot = exports.FINGERPRINT_POLL_INTERVAL_MS = void 0;
13
+ const backend_common_1 = require("@n8n/backend-common");
14
+ const constants_1 = require("@n8n/constants");
15
+ const decorators_1 = require("@n8n/decorators");
16
+ const di_1 = require("@n8n/di");
17
+ const publisher_service_1 = require("../../scaling/pubsub/publisher.service");
18
+ const type_availability_policy_attachment_repository_1 = require("./database/repositories/type-availability-policy-attachment.repository");
19
+ const type_availability_policy_scope_repository_1 = require("./database/repositories/type-availability-policy-scope.repository");
20
+ const effective_policy_1 = require("./effective-policy");
21
+ exports.FINGERPRINT_POLL_INTERVAL_MS = 30 * constants_1.Time.seconds.toMilliseconds;
22
+ function scopeKey(kind, projectId) {
23
+ return `${kind}:${projectId ?? 'instance'}`;
24
+ }
25
+ function sameFingerprint(a, b) {
26
+ return (a.count === b.count && a.versionSum === b.versionSum && a.newestCreatedAt === b.newestCreatedAt);
27
+ }
28
+ let TypeAvailabilityPolicySnapshot = class TypeAvailabilityPolicySnapshot {
29
+ constructor(scopeRepository, attachmentRepository, publisher, logger) {
30
+ this.scopeRepository = scopeRepository;
31
+ this.attachmentRepository = attachmentRepository;
32
+ this.publisher = publisher;
33
+ this.logger = logger;
34
+ this.loaded = null;
35
+ this.queue = Promise.resolve();
36
+ this.pending = null;
37
+ this.polling = false;
38
+ this.logger = this.logger.scoped('policy');
39
+ }
40
+ read(kind, projectId) {
41
+ if (!this.loaded)
42
+ return null;
43
+ return this.loaded.scopes.get(scopeKey(kind, projectId)) ?? (0, effective_policy_1.unconfiguredScope)(kind, projectId);
44
+ }
45
+ projectScopes(kind) {
46
+ if (!this.loaded)
47
+ return null;
48
+ return [...this.loaded.scopes.values()].filter((scope) => scope.kind === kind && scope.projectId !== null);
49
+ }
50
+ async start() {
51
+ await this.reloadAndLog();
52
+ this.pollTimer ??= setInterval(async () => await this.poll(), exports.FINGERPRINT_POLL_INTERVAL_MS);
53
+ this.pollTimer.unref();
54
+ }
55
+ stop() {
56
+ clearInterval(this.pollTimer);
57
+ this.pollTimer = undefined;
58
+ }
59
+ async refreshAfterWrite() {
60
+ await this.reloadAndLog();
61
+ void this.publisher
62
+ .publishCommand({ command: 'reload-type-availability-policies' })
63
+ .catch((error) => {
64
+ this.logger.warn('Failed to tell other processes to reload type availability policies', {
65
+ error,
66
+ });
67
+ });
68
+ }
69
+ async handleReloadRequest() {
70
+ await this.reloadAndLog();
71
+ }
72
+ async reload() {
73
+ this.pending ??= this.queue.then(async () => {
74
+ this.pending = null;
75
+ await this.load();
76
+ });
77
+ const pending = this.pending;
78
+ this.queue = pending.catch(() => { });
79
+ await pending;
80
+ }
81
+ async reloadAndLog() {
82
+ try {
83
+ await this.reload();
84
+ }
85
+ catch (error) {
86
+ this.logger.error('Failed to load type availability policies', { error });
87
+ }
88
+ }
89
+ async load() {
90
+ const fingerprint = await this.scopeRepository.readFingerprint({});
91
+ const scopes = await this.scopeRepository.findAllScopes({});
92
+ const attachmentsByScope = await this.attachmentRepository.listAttachmentsForScopes(scopes.map((scope) => scope.id), {});
93
+ const byKey = new Map();
94
+ for (const scope of scopes) {
95
+ byKey.set(scopeKey(scope.kind, scope.projectId), (0, effective_policy_1.toEffectivePolicy)(scope, attachmentsByScope.get(scope.id) ?? []));
96
+ }
97
+ this.loaded = { scopes: byKey, fingerprint };
98
+ }
99
+ async poll() {
100
+ if (this.polling)
101
+ return;
102
+ this.polling = true;
103
+ try {
104
+ if (this.loaded) {
105
+ const fingerprint = await this.scopeRepository.readFingerprint({});
106
+ if (sameFingerprint(fingerprint, this.loaded.fingerprint))
107
+ return;
108
+ this.logger.info('Type availability policies changed without a reload message');
109
+ }
110
+ await this.reload();
111
+ }
112
+ catch (error) {
113
+ this.logger.error('Failed to check type availability policies for changes', { error });
114
+ }
115
+ finally {
116
+ this.polling = false;
117
+ }
118
+ }
119
+ };
120
+ exports.TypeAvailabilityPolicySnapshot = TypeAvailabilityPolicySnapshot;
121
+ __decorate([
122
+ (0, decorators_1.OnShutdown)(),
123
+ __metadata("design:type", Function),
124
+ __metadata("design:paramtypes", []),
125
+ __metadata("design:returntype", void 0)
126
+ ], TypeAvailabilityPolicySnapshot.prototype, "stop", null);
127
+ __decorate([
128
+ (0, decorators_1.OnPubSubEvent)('reload-type-availability-policies'),
129
+ (0, decorators_1.OnPubSubEvent)('pubsub-reconnected'),
130
+ __metadata("design:type", Function),
131
+ __metadata("design:paramtypes", []),
132
+ __metadata("design:returntype", Promise)
133
+ ], TypeAvailabilityPolicySnapshot.prototype, "handleReloadRequest", null);
134
+ exports.TypeAvailabilityPolicySnapshot = TypeAvailabilityPolicySnapshot = __decorate([
135
+ (0, di_1.Service)(),
136
+ __metadata("design:paramtypes", [type_availability_policy_scope_repository_1.TypeAvailabilityPolicyScopeRepository, type_availability_policy_attachment_repository_1.TypeAvailabilityPolicyAttachmentRepository, publisher_service_1.Publisher, backend_common_1.Logger])
137
+ ], TypeAvailabilityPolicySnapshot);
138
+ //# sourceMappingURL=type-availability-policy-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-availability-policy-snapshot.js","sourceRoot":"","sources":["../../../src/modules/type-availability-policies/type-availability-policy-snapshot.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import type { NodeTypeAvailabilityScope } from '@n8n/api-types';
2
- import { Logger } from '@n8n/backend-common';
3
- import { CacheService, EventService } from '@n8n/backend-services';
2
+ import { EventService } from '@n8n/backend-services';
4
3
  import { TransactionRunner, type OperationContext } from '@n8n/db';
5
4
  import { LoadNodesAndCredentials } from '../../load-nodes-and-credentials';
6
5
  import { NodeTypes } from '../../node-types';
@@ -9,24 +8,17 @@ import { TypeAvailabilityPolicyScopeRepository } from './database/repositories/t
9
8
  import { TypeAvailabilityPolicyRepository } from './database/repositories/type-availability-policy.repository';
10
9
  import type { TypeAvailabilityPolicy } from './database/entities/type-availability-policy.entity';
11
10
  import type { TypeAvailabilityPolicyScope } from './database/entities/type-availability-policy-scope.entity';
11
+ import { type EffectivePolicy } from './effective-policy';
12
12
  import { type ComposedVerdict } from './policy-evaluator';
13
13
  import type { PolicyAction, PolicyAttachment, PolicyRule } from './policy-rule.types';
14
14
  import { type PolicyRuleWarning } from './policy-rule-lint';
15
- export declare const LOCAL_READ_MAX_ENTRIES = 512;
15
+ import { TypeAvailabilityPolicySnapshot } from './type-availability-policy-snapshot';
16
+ export type { EffectivePolicy } from './effective-policy';
16
17
  export type AttachmentInput = {
17
18
  readonly policyId: string;
18
19
  readonly priority: number;
19
20
  readonly isFloor: boolean;
20
21
  };
21
- export type EffectivePolicy = {
22
- readonly scopeId: string | null;
23
- readonly kind: string;
24
- readonly projectId: string | null;
25
- readonly defaultAction: PolicyAction;
26
- readonly version: number;
27
- readonly rules: readonly PolicyRule[];
28
- readonly attachments: readonly PolicyAttachment[];
29
- };
30
22
  export type ScopeAttachments = {
31
23
  readonly attachments: readonly PolicyAttachment[];
32
24
  readonly version: number;
@@ -51,14 +43,10 @@ export declare class TypeAvailabilityPolicyService {
51
43
  private readonly attachmentRepository;
52
44
  private readonly transactionRunner;
53
45
  private readonly eventService;
54
- private readonly cacheService;
46
+ private readonly snapshot;
55
47
  private readonly loadNodesAndCredentials;
56
48
  private readonly nodeTypes;
57
- private readonly logger;
58
- constructor(policyRepository: TypeAvailabilityPolicyRepository, scopeRepository: TypeAvailabilityPolicyScopeRepository, attachmentRepository: TypeAvailabilityPolicyAttachmentRepository, transactionRunner: TransactionRunner, eventService: EventService, cacheService: CacheService, loadNodesAndCredentials: LoadNodesAndCredentials, nodeTypes: NodeTypes, logger: Logger);
59
- private readonly localReads;
60
- private invalidations;
61
- private readonly repeatDeletes;
49
+ constructor(policyRepository: TypeAvailabilityPolicyRepository, scopeRepository: TypeAvailabilityPolicyScopeRepository, attachmentRepository: TypeAvailabilityPolicyAttachmentRepository, transactionRunner: TransactionRunner, eventService: EventService, snapshot: TypeAvailabilityPolicySnapshot, loadNodesAndCredentials: LoadNodesAndCredentials, nodeTypes: NodeTypes);
62
50
  getEffectivePolicy(kind: string, projectId: string | null, ctx?: OperationContext): Promise<EffectivePolicy>;
63
51
  setDefaultAction(kind: string, projectId: string | null, defaultAction: PolicyAction, expectedVersion: number, updatedBy: string): Promise<TypeAvailabilityPolicyScope>;
64
52
  private createScopeOrConflict;
@@ -96,11 +84,6 @@ export declare class TypeAvailabilityPolicyService {
96
84
  }>;
97
85
  private verdictComposer;
98
86
  private readComposedScopes;
99
- private readEffectivePolicyCached;
100
- private readScope;
101
- private canPublish;
102
- resetLocalCaches(): void;
103
- private invalidateScopes;
104
- private dropCacheKeys;
87
+ private readEnforcedScope;
88
+ private readProjectScopes;
105
89
  }
106
- export {};
@@ -9,13 +9,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.TypeAvailabilityPolicyService = exports.LOCAL_READ_MAX_ENTRIES = void 0;
13
- const backend_common_1 = require("@n8n/backend-common");
12
+ exports.TypeAvailabilityPolicyService = void 0;
14
13
  const backend_services_1 = require("@n8n/backend-services");
15
- const constants_1 = require("@n8n/constants");
16
14
  const db_1 = require("@n8n/db");
17
15
  const di_1 = require("@n8n/di");
18
- const lru_cache_1 = require("lru-cache");
19
16
  const n8n_workflow_1 = require("n8n-workflow");
20
17
  const errors_1 = require("@n8n/errors");
21
18
  const load_nodes_and_credentials_1 = require("../../load-nodes-and-credentials");
@@ -23,56 +20,12 @@ const node_types_1 = require("../../node-types");
23
20
  const type_availability_policy_attachment_repository_1 = require("./database/repositories/type-availability-policy-attachment.repository");
24
21
  const type_availability_policy_scope_repository_1 = require("./database/repositories/type-availability-policy-scope.repository");
25
22
  const type_availability_policy_repository_1 = require("./database/repositories/type-availability-policy.repository");
26
- const constants_2 = require("./constants");
23
+ const constants_1 = require("./constants");
24
+ const effective_policy_1 = require("./effective-policy");
27
25
  const package_resolver_1 = require("./package-resolver");
28
26
  const policy_evaluator_1 = require("./policy-evaluator");
29
27
  const policy_rule_lint_1 = require("./policy-rule-lint");
30
- const UNCONFIGURED_VERSION = 0;
31
- const SCOPE_CACHE_TTL_MS = 10 * constants_1.Time.minutes.toMilliseconds;
32
- const LOCAL_READ_TTL_MS = 1 * constants_1.Time.seconds.toMilliseconds;
33
- exports.LOCAL_READ_MAX_ENTRIES = 512;
34
- const INVALIDATION_REPEAT_DELAY_MS = 1 * constants_1.Time.seconds.toMilliseconds;
35
- const CACHE_CALL_TIMEOUT_MS = 50;
36
- function scopeCacheKey(kind, projectId) {
37
- return `type-availability-policy:scope:${kind}:${projectId ?? 'instance'}`;
38
- }
39
- async function withCacheTimeout(call) {
40
- call.catch(() => { });
41
- let timer;
42
- try {
43
- return await Promise.race([
44
- call,
45
- new Promise((_, reject) => {
46
- timer = setTimeout(() => reject(new n8n_workflow_1.OperationalError('Policy cache call timed out')), CACHE_CALL_TIMEOUT_MS);
47
- }),
48
- ]);
49
- }
50
- finally {
51
- clearTimeout(timer);
52
- }
53
- }
54
- const UNCONFIGURED_PROJECT = {
55
- scopeId: null,
56
- projectId: null,
57
- defaultAction: 'allow',
58
- version: UNCONFIGURED_VERSION,
59
- rules: [],
60
- attachments: [],
61
- };
62
- function toEffectivePolicy(scope, attachments) {
63
- return {
64
- scopeId: scope.id,
65
- kind: scope.kind,
66
- projectId: scope.projectId,
67
- defaultAction: scope.defaultAction,
68
- version: scope.version,
69
- rules: flattenRules(attachments),
70
- attachments,
71
- };
72
- }
73
- function flattenRules(attachments) {
74
- return (0, policy_evaluator_1.orderedAttachments)(attachments).flatMap((attachment) => [...attachment.rules]);
75
- }
28
+ const type_availability_policy_snapshot_1 = require("./type-availability-policy-snapshot");
76
29
  function rulesContainDelegate(rules) {
77
30
  return rules.some((rule) => rule.action === 'delegate');
78
31
  }
@@ -88,7 +41,7 @@ function assertNoDelegateAtProjectScope(projectId, defaultAction, rules = []) {
88
41
  }
89
42
  }
90
43
  function assertNoCredentialOnlyNodeRules(kind, rules) {
91
- if (kind !== constants_2.NODE_TYPES_KIND)
44
+ if (kind !== constants_1.NODE_TYPES_KIND)
92
45
  return;
93
46
  for (const rule of rules) {
94
47
  if (rule.selector.kind === 'name' && (0, n8n_workflow_1.isCredentialOnlyNodeType)(rule.selector.value)) {
@@ -105,7 +58,7 @@ function assertNoCredentialOnlyPackageRules(rules) {
105
58
  }
106
59
  }
107
60
  function assertExtendsSelectorsValid(kind, rules) {
108
- if (kind === constants_2.CREDENTIAL_TYPES_KIND)
61
+ if (kind === constants_1.CREDENTIAL_TYPES_KIND)
109
62
  return;
110
63
  if (rules.some((rule) => rule.selector.kind === 'extends')) {
111
64
  throw new n8n_workflow_1.UserError('An "extends" rule is only valid in a credential type policy');
@@ -127,42 +80,28 @@ function assertNoDuplicateAttachmentSlots(attachments) {
127
80
  }
128
81
  }
129
82
  let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
130
- constructor(policyRepository, scopeRepository, attachmentRepository, transactionRunner, eventService, cacheService, loadNodesAndCredentials, nodeTypes, logger) {
83
+ constructor(policyRepository, scopeRepository, attachmentRepository, transactionRunner, eventService, snapshot, loadNodesAndCredentials, nodeTypes) {
131
84
  this.policyRepository = policyRepository;
132
85
  this.scopeRepository = scopeRepository;
133
86
  this.attachmentRepository = attachmentRepository;
134
87
  this.transactionRunner = transactionRunner;
135
88
  this.eventService = eventService;
136
- this.cacheService = cacheService;
89
+ this.snapshot = snapshot;
137
90
  this.loadNodesAndCredentials = loadNodesAndCredentials;
138
91
  this.nodeTypes = nodeTypes;
139
- this.logger = logger;
140
- this.localReads = new lru_cache_1.LRUCache({ max: exports.LOCAL_READ_MAX_ENTRIES });
141
- this.invalidations = 0;
142
- this.repeatDeletes = new Set();
143
- this.logger = this.logger.scoped('policy');
144
92
  }
145
93
  async getEffectivePolicy(kind, projectId, ctx = {}) {
146
94
  const scope = await this.scopeRepository.findScopeByKindAndProject(kind, projectId, ctx);
147
- if (!scope) {
148
- return {
149
- scopeId: null,
150
- kind,
151
- projectId,
152
- defaultAction: 'allow',
153
- version: UNCONFIGURED_VERSION,
154
- rules: [],
155
- attachments: [],
156
- };
157
- }
95
+ if (!scope)
96
+ return (0, effective_policy_1.unconfiguredScope)(kind, projectId);
158
97
  const attachments = await this.attachmentRepository.listAttachmentsForScope(scope.id, ctx);
159
- return toEffectivePolicy(scope, attachments);
98
+ return (0, effective_policy_1.toEffectivePolicy)(scope, attachments);
160
99
  }
161
100
  async setDefaultAction(kind, projectId, defaultAction, expectedVersion, updatedBy) {
162
101
  assertNoDelegateAtProjectScope(projectId, defaultAction);
163
102
  const result = await this.transactionRunner.run({}, async (ctx) => {
164
103
  const scope = await this.scopeRepository.findScopeByKindAndProject(kind, projectId, ctx, true);
165
- const currentVersion = scope?.version ?? UNCONFIGURED_VERSION;
104
+ const currentVersion = scope?.version ?? effective_policy_1.UNCONFIGURED_VERSION;
166
105
  if (currentVersion !== expectedVersion) {
167
106
  throw new errors_1.ConflictError(`Policy scope has changed since it was last read (expected version ${expectedVersion}, found ${currentVersion})`);
168
107
  }
@@ -176,7 +115,7 @@ let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
176
115
  return { before, after };
177
116
  });
178
117
  if (result.before === null || result.before.version !== result.after.version) {
179
- await this.invalidateScopes([{ kind, projectId }]);
118
+ await this.snapshot.refreshAfterWrite();
180
119
  }
181
120
  this.eventService.emit('node-type-policy-scope-updated', {
182
121
  updatedBy,
@@ -191,7 +130,7 @@ let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
191
130
  async createScopeOrConflict(input, ctx) {
192
131
  const { scope, created } = await this.scopeRepository.createScopeIfAbsent(input, ctx);
193
132
  if (!created) {
194
- throw new errors_1.ConflictError(`Policy scope was created concurrently (expected version ${UNCONFIGURED_VERSION}, found ${scope.version})`);
133
+ throw new errors_1.ConflictError(`Policy scope was created concurrently (expected version ${effective_policy_1.UNCONFIGURED_VERSION}, found ${scope.version})`);
195
134
  }
196
135
  return scope;
197
136
  }
@@ -220,7 +159,7 @@ let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
220
159
  async updatePolicyDocument(kind, policyId, rules, expectedVersion, updatedBy) {
221
160
  const warnings = this.validateAndLintRules(kind, rules);
222
161
  const result = await this.transactionRunner.run({}, async (ctx) => {
223
- let invalidated = [];
162
+ let scopesChanged = false;
224
163
  const attachedScopeIds = await this.attachmentRepository.listScopeIdsAttachedToPolicy(policyId, ctx);
225
164
  const lockedScopeIds = await this.scopeRepository.lockScopesByIds(attachedScopeIds, ctx);
226
165
  if (rulesContainDelegate(rules) &&
@@ -245,11 +184,12 @@ let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
245
184
  throw new errors_1.ConflictError('Policy document was attached to another scope while it was being updated');
246
185
  }
247
186
  await this.scopeRepository.bumpVersions(lockedScopeIds, ctx);
248
- invalidated = await this.scopeRepository.findScopeKeysByIds(lockedScopeIds, ctx);
187
+ scopesChanged = lockedScopeIds.length > 0;
249
188
  }
250
- return { existing, updated, invalidated };
189
+ return { existing, updated, scopesChanged };
251
190
  });
252
- await this.invalidateScopes(result.invalidated);
191
+ if (result.scopesChanged)
192
+ await this.snapshot.refreshAfterWrite();
253
193
  this.eventService.emit('node-type-policy-document-updated', {
254
194
  updatedBy,
255
195
  kind: result.existing.kind,
@@ -331,7 +271,7 @@ let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
331
271
  versionAfter: scopeAfter?.version ?? scope.version + 1,
332
272
  };
333
273
  });
334
- await this.invalidateScopes([{ kind: result.kind, projectId: result.projectId }]);
274
+ await this.snapshot.refreshAfterWrite();
335
275
  this.eventService.emit('node-type-policy-attachments-updated', {
336
276
  updatedBy,
337
277
  kind: result.kind,
@@ -347,7 +287,7 @@ let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
347
287
  const warnings = this.validateAndLintRules(kind, input.rules);
348
288
  const result = await this.transactionRunner.run({}, async (ctx) => {
349
289
  const scope = await this.scopeRepository.findScopeByKindAndProject(kind, projectId, ctx, true);
350
- const currentVersion = scope?.version ?? UNCONFIGURED_VERSION;
290
+ const currentVersion = scope?.version ?? effective_policy_1.UNCONFIGURED_VERSION;
351
291
  if (currentVersion !== expectedVersion) {
352
292
  throw new errors_1.ConflictError(`Policy scope has changed since it was last read (expected version ${expectedVersion}, found ${currentVersion})`);
353
293
  }
@@ -420,7 +360,7 @@ let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
420
360
  policyId,
421
361
  };
422
362
  });
423
- await this.invalidateScopes([{ kind, projectId }]);
363
+ await this.snapshot.refreshAfterWrite();
424
364
  this.eventService.emit('node-type-policy-scope-updated', {
425
365
  updatedBy,
426
366
  kind,
@@ -444,7 +384,7 @@ let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
444
384
  kind,
445
385
  policyId: result.policyId,
446
386
  origin: 'composed-save',
447
- before: result.documentBefore ?? { rules: [], version: UNCONFIGURED_VERSION },
387
+ before: result.documentBefore ?? { rules: [], version: effective_policy_1.UNCONFIGURED_VERSION },
448
388
  after: result.documentAfter,
449
389
  });
450
390
  }
@@ -487,17 +427,16 @@ let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
487
427
  };
488
428
  }
489
429
  async evaluateComposedTypesForAllProjects(kind, typeNames) {
490
- const [instance, scopes] = await Promise.all([
491
- this.readEffectivePolicyCached(kind, null),
492
- this.scopeRepository.findProjectScopes(kind, {}),
430
+ const [instance, projects] = await Promise.all([
431
+ this.readEnforcedScope(kind, null),
432
+ this.snapshot.projectScopes(kind) ?? this.readProjectScopes(kind),
493
433
  ]);
494
- const attachmentsByScope = await this.attachmentRepository.listAttachmentsForScopes(scopes.map((scope) => scope.id), {});
495
434
  const composeVerdicts = this.verdictComposer(kind, typeNames);
496
435
  return {
497
- withoutProjectPolicy: composeVerdicts(instance, { ...UNCONFIGURED_PROJECT, kind }),
498
- byProject: scopes.map((scope) => ({
499
- projectId: scope.projectId,
500
- verdicts: composeVerdicts(instance, toEffectivePolicy(scope, attachmentsByScope.get(scope.id) ?? [])),
436
+ withoutProjectPolicy: composeVerdicts(instance, (0, effective_policy_1.unconfiguredScope)(kind, null)),
437
+ byProject: projects.map((project) => ({
438
+ projectId: project.projectId,
439
+ verdicts: composeVerdicts(instance, project),
501
440
  })),
502
441
  };
503
442
  }
@@ -510,95 +449,27 @@ let TypeAvailabilityPolicyService = class TypeAvailabilityPolicyService {
510
449
  }));
511
450
  }
512
451
  async readComposedScopes(kind, projectId) {
513
- if (projectId === null) {
514
- return {
515
- instance: await this.readEffectivePolicyCached(kind, null),
516
- project: { ...UNCONFIGURED_PROJECT, kind },
517
- };
518
- }
519
452
  const [instance, project] = await Promise.all([
520
- this.readEffectivePolicyCached(kind, null),
521
- this.readEffectivePolicyCached(kind, projectId),
453
+ this.readEnforcedScope(kind, null),
454
+ projectId === null ? (0, effective_policy_1.unconfiguredScope)(kind, null) : this.readEnforcedScope(kind, projectId),
522
455
  ]);
523
456
  return { instance, project };
524
457
  }
525
- async readEffectivePolicyCached(kind, projectId) {
526
- const key = scopeCacheKey(kind, projectId);
527
- const shared = this.localReads.get(key);
528
- if (shared && shared.expiresAt > Date.now())
529
- return await shared.read;
530
- const read = this.readScope(kind, projectId, key);
531
- read.catch(() => {
532
- if (this.localReads.peek(key)?.read === read)
533
- this.localReads.delete(key);
534
- });
535
- this.localReads.set(key, { read, expiresAt: Date.now() + LOCAL_READ_TTL_MS });
536
- return await read;
537
- }
538
- async readScope(kind, projectId, key) {
539
- const startedAt = Date.now();
540
- const invalidations = this.invalidations;
541
- try {
542
- const cached = await withCacheTimeout(this.cacheService.get(key));
543
- if (cached)
544
- return cached;
545
- }
546
- catch (error) {
547
- this.logger.warn('Failed to read the node type policy cache', { key, error });
548
- }
549
- const effective = await this.getEffectivePolicy(kind, projectId);
550
- if (!this.canPublish(invalidations, startedAt))
551
- return effective;
552
- try {
553
- await withCacheTimeout(this.cacheService.set(key, effective, SCOPE_CACHE_TTL_MS));
554
- }
555
- catch (error) {
556
- this.logger.warn('Failed to write the node type policy cache', { key, error });
557
- }
558
- return effective;
559
- }
560
- canPublish(invalidations, startedAt) {
561
- if (this.invalidations !== invalidations)
562
- return false;
563
- return Date.now() - startedAt < INVALIDATION_REPEAT_DELAY_MS;
564
- }
565
- resetLocalCaches() {
566
- this.localReads.clear();
567
- this.invalidations += 1;
568
- for (const repeat of this.repeatDeletes)
569
- clearTimeout(repeat);
570
- this.repeatDeletes.clear();
458
+ async readEnforcedScope(kind, projectId) {
459
+ return this.snapshot.read(kind, projectId) ?? (await this.getEffectivePolicy(kind, projectId));
571
460
  }
572
- async invalidateScopes(keys) {
573
- if (keys.length === 0)
574
- return;
575
- const cacheKeys = keys.map(({ kind, projectId }) => scopeCacheKey(kind, projectId));
576
- this.invalidations += 1;
577
- for (const key of cacheKeys)
578
- this.localReads.delete(key);
579
- await this.dropCacheKeys(cacheKeys);
580
- const repeat = setTimeout(async () => {
581
- this.repeatDeletes.delete(repeat);
582
- await this.dropCacheKeys(cacheKeys);
583
- }, INVALIDATION_REPEAT_DELAY_MS);
584
- repeat.unref();
585
- this.repeatDeletes.add(repeat);
586
- }
587
- async dropCacheKeys(cacheKeys) {
588
- try {
589
- await withCacheTimeout(this.cacheService.deleteMany(cacheKeys));
590
- }
591
- catch (error) {
592
- this.logger.error('Failed to invalidate the node type policy cache', {
593
- keys: cacheKeys,
594
- error,
595
- });
596
- }
461
+ async readProjectScopes(kind) {
462
+ const scopes = await this.scopeRepository.findProjectScopes(kind, {});
463
+ const attachmentsByScope = await this.attachmentRepository.listAttachmentsForScopes(scopes.map((scope) => scope.id), {});
464
+ return scopes.map((scope) => ({
465
+ ...(0, effective_policy_1.toEffectivePolicy)(scope, attachmentsByScope.get(scope.id) ?? []),
466
+ projectId: scope.projectId,
467
+ }));
597
468
  }
598
469
  };
599
470
  exports.TypeAvailabilityPolicyService = TypeAvailabilityPolicyService;
600
471
  exports.TypeAvailabilityPolicyService = TypeAvailabilityPolicyService = __decorate([
601
472
  (0, di_1.Service)(),
602
- __metadata("design:paramtypes", [type_availability_policy_repository_1.TypeAvailabilityPolicyRepository, type_availability_policy_scope_repository_1.TypeAvailabilityPolicyScopeRepository, type_availability_policy_attachment_repository_1.TypeAvailabilityPolicyAttachmentRepository, db_1.TransactionRunner, backend_services_1.EventService, backend_services_1.CacheService, load_nodes_and_credentials_1.LoadNodesAndCredentials, node_types_1.NodeTypes, backend_common_1.Logger])
473
+ __metadata("design:paramtypes", [type_availability_policy_repository_1.TypeAvailabilityPolicyRepository, type_availability_policy_scope_repository_1.TypeAvailabilityPolicyScopeRepository, type_availability_policy_attachment_repository_1.TypeAvailabilityPolicyAttachmentRepository, db_1.TransactionRunner, backend_services_1.EventService, type_availability_policy_snapshot_1.TypeAvailabilityPolicySnapshot, load_nodes_and_credentials_1.LoadNodesAndCredentials, node_types_1.NodeTypes])
603
474
  ], TypeAvailabilityPolicyService);
604
475
  //# sourceMappingURL=type-availability-policy.service.js.map