@marinoscar/platform-api 0.1.0-next.26 → 0.1.0-next.27

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 (57) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/manifest/platform-model-ownership.d.ts.map +1 -1
  3. package/dist/manifest/platform-model-ownership.js +19 -0
  4. package/dist/manifest/platform-model-ownership.js.map +1 -1
  5. package/dist/manifest/platform-user-owned-models.d.ts.map +1 -1
  6. package/dist/manifest/platform-user-owned-models.js +15 -0
  7. package/dist/manifest/platform-user-owned-models.js.map +1 -1
  8. package/dist/storage/config/storage-config.module.d.ts.map +1 -1
  9. package/dist/storage/config/storage-config.module.js +10 -1
  10. package/dist/storage/config/storage-config.module.js.map +1 -1
  11. package/dist/storage/data/storage-db.d.ts +118 -1
  12. package/dist/storage/data/storage-db.d.ts.map +1 -1
  13. package/dist/storage/data/storage-db.js +25 -1
  14. package/dist/storage/data/storage-db.js.map +1 -1
  15. package/dist/storage/index.d.ts +5 -2
  16. package/dist/storage/index.d.ts.map +1 -1
  17. package/dist/storage/index.js +25 -1
  18. package/dist/storage/index.js.map +1 -1
  19. package/dist/storage/migration/copy-and-verify.d.ts +39 -0
  20. package/dist/storage/migration/copy-and-verify.d.ts.map +1 -0
  21. package/dist/storage/migration/copy-and-verify.js +94 -0
  22. package/dist/storage/migration/copy-and-verify.js.map +1 -0
  23. package/dist/storage/migration/dto/storage-migration.dto.d.ts +73 -0
  24. package/dist/storage/migration/dto/storage-migration.dto.d.ts.map +1 -0
  25. package/dist/storage/migration/dto/storage-migration.dto.js +34 -0
  26. package/dist/storage/migration/dto/storage-migration.dto.js.map +1 -0
  27. package/dist/storage/migration/index.d.ts +11 -0
  28. package/dist/storage/migration/index.d.ts.map +1 -0
  29. package/dist/storage/migration/index.js +27 -0
  30. package/dist/storage/migration/index.js.map +1 -0
  31. package/dist/storage/migration/storage-migrate-object.handler.d.ts +40 -0
  32. package/dist/storage/migration/storage-migrate-object.handler.d.ts.map +1 -0
  33. package/dist/storage/migration/storage-migrate-object.handler.js +177 -0
  34. package/dist/storage/migration/storage-migrate-object.handler.js.map +1 -0
  35. package/dist/storage/migration/storage-migrate-plan.handler.d.ts +34 -0
  36. package/dist/storage/migration/storage-migrate-plan.handler.d.ts.map +1 -0
  37. package/dist/storage/migration/storage-migrate-plan.handler.js +168 -0
  38. package/dist/storage/migration/storage-migrate-plan.handler.js.map +1 -0
  39. package/dist/storage/migration/storage-migration-settled.listener.d.ts +15 -0
  40. package/dist/storage/migration/storage-migration-settled.listener.d.ts.map +1 -0
  41. package/dist/storage/migration/storage-migration-settled.listener.js +87 -0
  42. package/dist/storage/migration/storage-migration-settled.listener.js.map +1 -0
  43. package/dist/storage/migration/storage-migration.constants.d.ts +69 -0
  44. package/dist/storage/migration/storage-migration.constants.d.ts.map +1 -0
  45. package/dist/storage/migration/storage-migration.constants.js +83 -0
  46. package/dist/storage/migration/storage-migration.constants.js.map +1 -0
  47. package/dist/storage/migration/storage-migration.controller.d.ts +26 -0
  48. package/dist/storage/migration/storage-migration.controller.d.ts.map +1 -0
  49. package/dist/storage/migration/storage-migration.controller.js +135 -0
  50. package/dist/storage/migration/storage-migration.controller.js.map +1 -0
  51. package/dist/storage/migration/storage-migration.service.d.ts +182 -0
  52. package/dist/storage/migration/storage-migration.service.d.ts.map +1 -0
  53. package/dist/storage/migration/storage-migration.service.js +444 -0
  54. package/dist/storage/migration/storage-migration.service.js.map +1 -0
  55. package/dist/storage/ports.d.ts +1 -1
  56. package/dist/storage/ports.d.ts.map +1 -1
  57. package/package.json +3 -3
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ // =============================================================================
3
+ // `storage.migrate_plan` — list a migration run's objects and queue them
4
+ // (issue #1093)
5
+ // =============================================================================
6
+ //
7
+ // One job per run, a system job (`orgId: null`): the run is deployment-wide and
8
+ // its objects belong to every organization, so it works through the bypass
9
+ // client with the `storage-migration` reason.
10
+ //
11
+ // RESUMABLE. Items are created page by page (keyset on the object id) with
12
+ // `skipDuplicates` against `@@unique([runId, objectId])`, and only items with no
13
+ // `jobId` are queued, so a planner that died half way and was retried continues
14
+ // where it stopped without a duplicate item or a duplicate job.
15
+ //
16
+ // WHAT IS COPIED: every `ready` object whose recorded `storage_provider` is the
17
+ // run's source. An object already repointed to the target is not on the source
18
+ // any more, so a re-run after a completed or cancelled run skips it for free.
19
+ //
20
+ // CANCELLATION is checked before every page; a cancelled run stops planning.
21
+ //
22
+ // SERVER-ONLY BY DERIVATION: no `nodeResultSchema` / `persistNodeResult`.
23
+ // =============================================================================
24
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
25
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
26
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
27
+ 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;
28
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
29
+ };
30
+ var __metadata = (this && this.__metadata) || function (k, v) {
31
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
32
+ };
33
+ var StorageMigratePlanHandler_1;
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.StorageMigratePlanHandler = void 0;
36
+ const common_1 = require("@nestjs/common");
37
+ const index_1 = require("../../jobs/index");
38
+ const storage_db_1 = require("../data/storage-db");
39
+ const storage_migration_constants_1 = require("./storage-migration.constants");
40
+ const storage_migration_service_1 = require("./storage-migration.service");
41
+ /** Objects listed, and items queued, per page. */
42
+ const PAGE_SIZE = 500;
43
+ function readRunId(job) {
44
+ const payload = job.payload;
45
+ if (!payload || typeof payload.runId !== 'string') {
46
+ throw new Error(`${storage_migration_constants_1.STORAGE_MIGRATE_PLAN_TYPE} job ${job.id} has no runId in its payload`);
47
+ }
48
+ return payload.runId;
49
+ }
50
+ /**
51
+ * The server-only `storage.migrate_plan` job: creates one item per `ready` object on the run's source driver and queues one `storage.migrate_object` job per item, resumably; a planner that gives up fails its run.
52
+ *
53
+ * @stability experimental
54
+ */
55
+ let StorageMigratePlanHandler = StorageMigratePlanHandler_1 = class StorageMigratePlanHandler {
56
+ registry;
57
+ migrations;
58
+ jobs;
59
+ logger = new common_1.Logger(StorageMigratePlanHandler_1.name);
60
+ type = storage_migration_constants_1.STORAGE_MIGRATE_PLAN_TYPE;
61
+ label = 'Storage migration (plan)';
62
+ /** Listing and queueing a large deployment's objects is long but bounded work. */
63
+ profile = { maxRuntimeMs: 60 * 60_000, maxAttempts: 3 };
64
+ constructor(registry, migrations, jobs) {
65
+ this.registry = registry;
66
+ this.migrations = migrations;
67
+ this.jobs = jobs;
68
+ }
69
+ /** Self-registration. */
70
+ onModuleInit() {
71
+ this.registry.register(this);
72
+ }
73
+ /** Plans the run named in the payload. */
74
+ async process(job) {
75
+ const runId = readRunId(job);
76
+ const db = this.migrations.db();
77
+ const run = await db.storageMigrationRun.findUnique({ where: { id: runId } });
78
+ if (!run) {
79
+ this.logger.warn(`${this.type} job ${job.id}: run ${runId} no longer exists; nothing to plan`);
80
+ return;
81
+ }
82
+ if (run.status !== storage_db_1.StorageMigrationRunStatus.pending && run.status !== storage_db_1.StorageMigrationRunStatus.running) {
83
+ this.logger.log(`${this.type} job ${job.id}: run ${runId} is ${run.status}; nothing to plan`);
84
+ return;
85
+ }
86
+ await db.storageMigrationRun.updateMany({
87
+ where: { id: runId, status: storage_db_1.StorageMigrationRunStatus.pending },
88
+ data: { status: storage_db_1.StorageMigrationRunStatus.running, startedAt: new Date() },
89
+ });
90
+ // 1. One item per object on the source, keyset-paged.
91
+ let cursor;
92
+ for (;;) {
93
+ if (await this.cancelled(runId))
94
+ return;
95
+ const objects = await db.storageObject.findMany({
96
+ where: {
97
+ storageProvider: run.sourceProvider,
98
+ status: storage_db_1.StorageObjectStatus.ready,
99
+ ...(cursor ? { id: { gt: cursor } } : {}),
100
+ },
101
+ select: { id: true, orgId: true, size: true },
102
+ orderBy: { id: 'asc' },
103
+ take: PAGE_SIZE,
104
+ });
105
+ if (objects.length === 0)
106
+ break;
107
+ await db.storageMigrationItem.createMany({
108
+ data: objects.map((object) => ({
109
+ runId,
110
+ objectId: object.id,
111
+ orgId: object.orgId,
112
+ sizeBytes: object.size,
113
+ status: storage_db_1.StorageMigrationItemStatus.pending,
114
+ })),
115
+ skipDuplicates: true,
116
+ });
117
+ cursor = objects[objects.length - 1].id;
118
+ if (objects.length < PAGE_SIZE)
119
+ break;
120
+ }
121
+ // 2. One job per item that has none yet.
122
+ for (;;) {
123
+ if (await this.cancelled(runId))
124
+ return;
125
+ const items = await db.storageMigrationItem.findMany({
126
+ where: { runId, jobId: null, status: storage_db_1.StorageMigrationItemStatus.pending },
127
+ select: { id: true, objectId: true, orgId: true },
128
+ orderBy: { id: 'asc' },
129
+ take: PAGE_SIZE,
130
+ });
131
+ if (items.length === 0)
132
+ break;
133
+ for (const item of items) {
134
+ const queued = await this.jobs.enqueue({
135
+ type: storage_migration_constants_1.STORAGE_MIGRATE_OBJECT_TYPE,
136
+ reason: index_1.JobReason.backfill,
137
+ subjectType: storage_migration_constants_1.STORAGE_MIGRATION_ITEM_SUBJECT_TYPE,
138
+ subjectId: item.id,
139
+ payload: { runId, itemId: item.id },
140
+ priority: storage_migration_constants_1.STORAGE_MIGRATION_PRIORITY,
141
+ orgId: item.orgId,
142
+ skipDedup: true,
143
+ });
144
+ await db.storageMigrationItem.updateMany({ where: { id: item.id, jobId: null }, data: { jobId: queued.id } });
145
+ }
146
+ }
147
+ const total = await db.storageMigrationItem.count({ where: { runId } });
148
+ await db.storageMigrationRun.updateMany({
149
+ where: { id: runId, status: storage_db_1.StorageMigrationRunStatus.running },
150
+ data: { plannedAt: new Date(), totalCount: total },
151
+ });
152
+ this.logger.log(`Storage migration ${runId}: ${total} object(s) queued (${run.sourceProvider} -> ${run.targetProvider})`);
153
+ // Every item may already be done (or there were none): finalize now.
154
+ await this.migrations.finalizeIfDone(runId);
155
+ }
156
+ async cancelled(runId) {
157
+ const current = await this.migrations.db().storageMigrationRun.findUnique({ where: { id: runId }, select: { status: true } });
158
+ return !current || current.status !== storage_db_1.StorageMigrationRunStatus.running;
159
+ }
160
+ };
161
+ exports.StorageMigratePlanHandler = StorageMigratePlanHandler;
162
+ exports.StorageMigratePlanHandler = StorageMigratePlanHandler = StorageMigratePlanHandler_1 = __decorate([
163
+ (0, common_1.Injectable)(),
164
+ __metadata("design:paramtypes", [index_1.JobHandlerRegistry,
165
+ storage_migration_service_1.StorageMigrationService,
166
+ index_1.JobsService])
167
+ ], StorageMigratePlanHandler);
168
+ //# sourceMappingURL=storage-migrate-plan.handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-migrate-plan.handler.js","sourceRoot":"","sources":["../../../src/storage/migration/storage-migrate-plan.handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type JobSettledEvent } from '../../jobs/index';
2
+ import { StorageMigrationService } from './storage-migration.service';
3
+ /**
4
+ * Fails the run of a planner that gave up, and the item of an object job that gave up.
5
+ *
6
+ * @stability experimental
7
+ */
8
+ export declare class StorageMigrationSettledListener {
9
+ private readonly migrations;
10
+ private readonly logger;
11
+ constructor(migrations: StorageMigrationService);
12
+ /** Dispatches a failed migration job; ignores everything else. Never throws. */
13
+ onJobSettled(event: JobSettledEvent): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=storage-migration-settled.listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-migration-settled.listener.d.ts","sourceRoot":"","sources":["../../../src/storage/migration/storage-migration-settled.listener.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAQ3E,OAAO,EAAE,uBAAuB,EAA6B,MAAM,6BAA6B,CAAC;AAEjG;;;;GAIG;AACH,qBACa,+BAA+B;IAG9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAFvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoD;gBAE9C,UAAU,EAAE,uBAAuB;IAEhE,gFAAgF;IAE1E,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;CA6B1D"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ // =============================================================================
3
+ // StorageMigrationSettledListener: what happens when a migration job GIVES UP
4
+ // (issue #1093)
5
+ // =============================================================================
6
+ //
7
+ // A listener on `job.settled`, not an "is this my last attempt?" check inside
8
+ // `process`: a timeout or a dead executor never returns into `process`. ONE
9
+ // listener for both job types (the event has a bounded listener budget), and a
10
+ // few bounded writes each, never I/O (`on-event-no-io`):
11
+ //
12
+ // * `storage.migrate_plan` failed: the run is failed (its active slot freed,
13
+ // its queued items skipped).
14
+ // * `storage.migrate_object` failed: its still-open item is failed, the error
15
+ // recorded on the run, and the run finalized when that was the last item.
16
+ // =============================================================================
17
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
18
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20
+ 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;
21
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
22
+ };
23
+ var __metadata = (this && this.__metadata) || function (k, v) {
24
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
+ };
26
+ var StorageMigrationSettledListener_1;
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.StorageMigrationSettledListener = void 0;
29
+ const common_1 = require("@nestjs/common");
30
+ const event_emitter_1 = require("@nestjs/event-emitter");
31
+ const index_1 = require("../../jobs/index");
32
+ const storage_db_1 = require("../data/storage-db");
33
+ const storage_migration_constants_1 = require("./storage-migration.constants");
34
+ const storage_migration_service_1 = require("./storage-migration.service");
35
+ /**
36
+ * Fails the run of a planner that gave up, and the item of an object job that gave up.
37
+ *
38
+ * @stability experimental
39
+ */
40
+ let StorageMigrationSettledListener = StorageMigrationSettledListener_1 = class StorageMigrationSettledListener {
41
+ migrations;
42
+ logger = new common_1.Logger(StorageMigrationSettledListener_1.name);
43
+ constructor(migrations) {
44
+ this.migrations = migrations;
45
+ }
46
+ /** Dispatches a failed migration job; ignores everything else. Never throws. */
47
+ async onJobSettled(event) {
48
+ if (event.succeeded || !event.subjectId)
49
+ return;
50
+ const message = (0, storage_migration_service_1.storageMigrationErrorText)(event.lastError ?? 'no error recorded');
51
+ try {
52
+ if (event.type === storage_migration_constants_1.STORAGE_MIGRATE_PLAN_TYPE && event.subjectType === storage_migration_constants_1.STORAGE_MIGRATION_RUN_SUBJECT_TYPE) {
53
+ await this.migrations.failRun(event.subjectId, `The planner failed: ${message}`);
54
+ return;
55
+ }
56
+ if (event.type !== storage_migration_constants_1.STORAGE_MIGRATE_OBJECT_TYPE || event.subjectType !== storage_migration_constants_1.STORAGE_MIGRATION_ITEM_SUBJECT_TYPE)
57
+ return;
58
+ await this.migrations.db().storageMigrationItem.updateMany({
59
+ where: {
60
+ id: event.subjectId,
61
+ status: { in: [storage_db_1.StorageMigrationItemStatus.pending, storage_db_1.StorageMigrationItemStatus.copying] },
62
+ },
63
+ data: { status: storage_db_1.StorageMigrationItemStatus.failed, lastError: message },
64
+ });
65
+ const runId = event.job.payload?.runId;
66
+ if (typeof runId === 'string') {
67
+ await this.migrations.recordRunError(runId, message);
68
+ await this.migrations.finalizeIfDone(runId);
69
+ }
70
+ }
71
+ catch (error) {
72
+ this.logger.error(`Could not record the failure of ${event.type} job ${event.jobId}: ${(0, storage_migration_service_1.storageMigrationErrorText)(error)}`);
73
+ }
74
+ }
75
+ };
76
+ exports.StorageMigrationSettledListener = StorageMigrationSettledListener;
77
+ __decorate([
78
+ (0, event_emitter_1.OnEvent)(index_1.JOB_SETTLED_EVENT),
79
+ __metadata("design:type", Function),
80
+ __metadata("design:paramtypes", [Function]),
81
+ __metadata("design:returntype", Promise)
82
+ ], StorageMigrationSettledListener.prototype, "onJobSettled", null);
83
+ exports.StorageMigrationSettledListener = StorageMigrationSettledListener = StorageMigrationSettledListener_1 = __decorate([
84
+ (0, common_1.Injectable)(),
85
+ __metadata("design:paramtypes", [storage_migration_service_1.StorageMigrationService])
86
+ ], StorageMigrationSettledListener);
87
+ //# sourceMappingURL=storage-migration-settled.listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-migration-settled.listener.js","sourceRoot":"","sources":["../../../src/storage/migration/storage-migration-settled.listener.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,8EAA8E;AAC9E,gBAAgB;AAChB,gFAAgF;AAChF,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,+EAA+E;AAC/E,yDAAyD;AACzD,EAAE;AACF,+EAA+E;AAC/E,iCAAiC;AACjC,gFAAgF;AAChF,8EAA8E;AAC9E,gFAAgF;;;;;;;;;;;;;AAEhF,2CAAoD;AACpD,yDAAgD;AAEhD,4CAA2E;AAC3E,mDAAgE;AAChE,+EAKuC;AACvC,2EAAiG;AAEjG;;;;GAIG;AAEI,IAAM,+BAA+B,uCAArC,MAAM,+BAA+B;IAGb;IAFZ,MAAM,GAAG,IAAI,eAAM,CAAC,iCAA+B,CAAC,IAAI,CAAC,CAAC;IAE3E,YAA6B,UAAmC;QAAnC,eAAU,GAAV,UAAU,CAAyB;IAAG,CAAC;IAEpE,gFAAgF;IAE1E,AAAN,KAAK,CAAC,YAAY,CAAC,KAAsB;QACvC,IAAI,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,SAAS;YAAE,OAAO;QAChD,MAAM,OAAO,GAAG,IAAA,qDAAyB,EAAC,KAAK,CAAC,SAAS,IAAI,mBAAmB,CAAC,CAAC;QAElF,IAAI,CAAC;YACH,IAAI,KAAK,CAAC,IAAI,KAAK,uDAAyB,IAAI,KAAK,CAAC,WAAW,KAAK,gEAAkC,EAAE,CAAC;gBACzG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,uBAAuB,OAAO,EAAE,CAAC,CAAC;gBACjF,OAAO;YACT,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,yDAA2B,IAAI,KAAK,CAAC,WAAW,KAAK,iEAAmC;gBAAE,OAAO;YAEpH,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,UAAU,CAAC;gBACzD,KAAK,EAAE;oBACL,EAAE,EAAE,KAAK,CAAC,SAAS;oBACnB,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,uCAA0B,CAAC,OAAO,EAAE,uCAA0B,CAAC,OAAO,CAAC,EAAE;iBACzF;gBACD,IAAI,EAAE,EAAE,MAAM,EAAE,uCAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE;aACxE,CAAC,CAAC;YACH,MAAM,KAAK,GAAI,KAAK,CAAC,GAAG,CAAC,OAAsC,EAAE,KAAK,CAAC;YACvE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,MAAM,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBACrD,MAAM,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,mCAAmC,KAAK,CAAC,IAAI,QAAQ,KAAK,CAAC,KAAK,KAAK,IAAA,qDAAyB,EAAC,KAAK,CAAC,EAAE,CACxG,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAA;AApCY,0EAA+B;AAOpC;IADL,IAAA,uBAAO,EAAC,yBAAiB,CAAC;;;;mEA6B1B;0CAnCU,+BAA+B;IAD3C,IAAA,mBAAU,GAAE;qCAI8B,mDAAuB;GAHrD,+BAA+B,CAoC3C"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The job type that lists a run's objects, creates one item per object and
3
+ * queues one {@link STORAGE_MIGRATE_OBJECT_TYPE} job per item. PERMANENT:
4
+ * rows outlive handlers. Server-only (no `nodeResultSchema`).
5
+ *
6
+ * @stability experimental
7
+ */
8
+ export declare const STORAGE_MIGRATE_PLAN_TYPE = "storage.migrate_plan";
9
+ /**
10
+ * The job type that copies ONE object to the run's target driver, verifies it
11
+ * and repoints its row. PERMANENT. Server-only: it needs both drivers' secrets,
12
+ * which are never brokered to a worker node.
13
+ *
14
+ * @stability experimental
15
+ */
16
+ export declare const STORAGE_MIGRATE_OBJECT_TYPE = "storage.migrate_object";
17
+ /**
18
+ * The `subjectType` of a planner job (`subjectId` is the run id).
19
+ *
20
+ * @stability experimental
21
+ */
22
+ export declare const STORAGE_MIGRATION_RUN_SUBJECT_TYPE = "storage_migration_run";
23
+ /**
24
+ * The `subjectType` of a per-object job (`subjectId` is the item id).
25
+ *
26
+ * @stability experimental
27
+ */
28
+ export declare const STORAGE_MIGRATION_ITEM_SUBJECT_TYPE = "storage_migration_item";
29
+ /**
30
+ * The queue priority of both job types: background, the housekeeping value,
31
+ * so a migration never delays an upload's processing.
32
+ *
33
+ * @stability experimental
34
+ */
35
+ export declare const STORAGE_MIGRATION_PRIORITY: number;
36
+ /**
37
+ * The raw-SQL partial unique index that allows one pending or running run.
38
+ *
39
+ * @stability experimental
40
+ */
41
+ export declare const STORAGE_MIGRATION_ACTIVE_INDEX = "storage_migration_runs_active_uniq_idx";
42
+ /**
43
+ * The system access reason every migration query names: a run is
44
+ * deployment-wide (its `org_id` is NULL) and spans every organization's objects.
45
+ *
46
+ * @stability experimental
47
+ */
48
+ export declare const STORAGE_MIGRATION_SYSTEM_ACCESS_REASON = "storage-migration";
49
+ /**
50
+ * The audit actions the migration writes.
51
+ *
52
+ * @stability experimental
53
+ */
54
+ export declare const STORAGE_MIGRATION_AUDIT_ACTIONS: {
55
+ /** A run was started. */
56
+ readonly START: 'storage.migration.start';
57
+ /** A run was cancelled. */
58
+ readonly CANCEL: 'storage.migration.cancel';
59
+ };
60
+ /**
61
+ * Registers {@link STORAGE_MIGRATION_SYSTEM_ACCESS_REASON} with core's
62
+ * registry, once. The service and both handlers call it from their
63
+ * constructors (bootstrap, before the registry freezes), so code that builds
64
+ * them by hand (a database test) is covered too.
65
+ *
66
+ * @stability experimental
67
+ */
68
+ export declare function registerStorageMigrationSystemAccessReason(): void;
69
+ //# sourceMappingURL=storage-migration.constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-migration.constants.d.ts","sourceRoot":"","sources":["../../../src/storage/migration/storage-migration.constants.ts"],"names":[],"mappings":"AAOA;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,yBAAyB,CAAC;AAEhE;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AAEpE;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,0BAA0B,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,mCAAmC,2BAA2B,CAAC;AAE5E;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAA8B,CAAC;AAExE;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,2CAA2C,CAAC;AAEvF;;;;;GAKG;AACH,eAAO,MAAM,sCAAsC,sBAAsB,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,EAAE;IAC5C,yBAAyB;IACzB,QAAQ,CAAC,KAAK,EAAE,yBAAyB,CAAC;IAC1C,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;CAIpC,CAAC;AAEX;;;;;;;GAOG;AACH,wBAAgB,0CAA0C,IAAI,IAAI,CAOjE"}
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ // =============================================================================
3
+ // Copy-only storage provider migration: the permanent strings (issue #1093)
4
+ // =============================================================================
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.STORAGE_MIGRATION_AUDIT_ACTIONS = exports.STORAGE_MIGRATION_SYSTEM_ACCESS_REASON = exports.STORAGE_MIGRATION_ACTIVE_INDEX = exports.STORAGE_MIGRATION_PRIORITY = exports.STORAGE_MIGRATION_ITEM_SUBJECT_TYPE = exports.STORAGE_MIGRATION_RUN_SUBJECT_TYPE = exports.STORAGE_MIGRATE_OBJECT_TYPE = exports.STORAGE_MIGRATE_PLAN_TYPE = void 0;
7
+ exports.registerStorageMigrationSystemAccessReason = registerStorageMigrationSystemAccessReason;
8
+ const index_1 = require("../../core/index");
9
+ const index_2 = require("../../jobs/index");
10
+ /**
11
+ * The job type that lists a run's objects, creates one item per object and
12
+ * queues one {@link STORAGE_MIGRATE_OBJECT_TYPE} job per item. PERMANENT:
13
+ * rows outlive handlers. Server-only (no `nodeResultSchema`).
14
+ *
15
+ * @stability experimental
16
+ */
17
+ exports.STORAGE_MIGRATE_PLAN_TYPE = 'storage.migrate_plan';
18
+ /**
19
+ * The job type that copies ONE object to the run's target driver, verifies it
20
+ * and repoints its row. PERMANENT. Server-only: it needs both drivers' secrets,
21
+ * which are never brokered to a worker node.
22
+ *
23
+ * @stability experimental
24
+ */
25
+ exports.STORAGE_MIGRATE_OBJECT_TYPE = 'storage.migrate_object';
26
+ /**
27
+ * The `subjectType` of a planner job (`subjectId` is the run id).
28
+ *
29
+ * @stability experimental
30
+ */
31
+ exports.STORAGE_MIGRATION_RUN_SUBJECT_TYPE = 'storage_migration_run';
32
+ /**
33
+ * The `subjectType` of a per-object job (`subjectId` is the item id).
34
+ *
35
+ * @stability experimental
36
+ */
37
+ exports.STORAGE_MIGRATION_ITEM_SUBJECT_TYPE = 'storage_migration_item';
38
+ /**
39
+ * The queue priority of both job types: background, the housekeeping value,
40
+ * so a migration never delays an upload's processing.
41
+ *
42
+ * @stability experimental
43
+ */
44
+ exports.STORAGE_MIGRATION_PRIORITY = index_2.HOUSEKEEPING_PRIORITY;
45
+ /**
46
+ * The raw-SQL partial unique index that allows one pending or running run.
47
+ *
48
+ * @stability experimental
49
+ */
50
+ exports.STORAGE_MIGRATION_ACTIVE_INDEX = 'storage_migration_runs_active_uniq_idx';
51
+ /**
52
+ * The system access reason every migration query names: a run is
53
+ * deployment-wide (its `org_id` is NULL) and spans every organization's objects.
54
+ *
55
+ * @stability experimental
56
+ */
57
+ exports.STORAGE_MIGRATION_SYSTEM_ACCESS_REASON = 'storage-migration';
58
+ /**
59
+ * The audit actions the migration writes.
60
+ *
61
+ * @stability experimental
62
+ */
63
+ exports.STORAGE_MIGRATION_AUDIT_ACTIONS = {
64
+ START: 'storage.migration.start',
65
+ CANCEL: 'storage.migration.cancel',
66
+ };
67
+ /**
68
+ * Registers {@link STORAGE_MIGRATION_SYSTEM_ACCESS_REASON} with core's
69
+ * registry, once. The service and both handlers call it from their
70
+ * constructors (bootstrap, before the registry freezes), so code that builds
71
+ * them by hand (a database test) is covered too.
72
+ *
73
+ * @stability experimental
74
+ */
75
+ function registerStorageMigrationSystemAccessReason() {
76
+ if (index_1.systemAccessReasonRegistry.has(exports.STORAGE_MIGRATION_SYSTEM_ACCESS_REASON))
77
+ return;
78
+ (0, index_1.registerSystemAccessReason)({
79
+ id: exports.STORAGE_MIGRATION_SYSTEM_ACCESS_REASON,
80
+ description: 'Copy-only storage provider migration: deployment-wide runs (NULL org_id) and the objects of every organization they copy.',
81
+ });
82
+ }
83
+ //# sourceMappingURL=storage-migration.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-migration.constants.js","sourceRoot":"","sources":["../../../src/storage/migration/storage-migration.constants.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,4EAA4E;AAC5E,gFAAgF;;;AAmFhF,gGAOC;AAxFD,4CAA0F;AAC1F,4CAAyD;AAEzD;;;;;;GAMG;AACU,QAAA,yBAAyB,GAAG,sBAAsB,CAAC;AAEhE;;;;;;GAMG;AACU,QAAA,2BAA2B,GAAG,wBAAwB,CAAC;AAEpE;;;;GAIG;AACU,QAAA,kCAAkC,GAAG,uBAAuB,CAAC;AAE1E;;;;GAIG;AACU,QAAA,mCAAmC,GAAG,wBAAwB,CAAC;AAE5E;;;;;GAKG;AACU,QAAA,0BAA0B,GAAW,6BAAqB,CAAC;AAExE;;;;GAIG;AACU,QAAA,8BAA8B,GAAG,wCAAwC,CAAC;AAEvF;;;;;GAKG;AACU,QAAA,sCAAsC,GAAG,mBAAmB,CAAC;AAE1E;;;;GAIG;AACU,QAAA,+BAA+B,GAKxC;IACF,KAAK,EAAE,yBAAyB;IAChC,MAAM,EAAE,0BAA0B;CAC1B,CAAC;AAEX;;;;;;;GAOG;AACH,SAAgB,0CAA0C;IACxD,IAAI,kCAA0B,CAAC,GAAG,CAAC,8CAAsC,CAAC;QAAE,OAAO;IACnF,IAAA,kCAA0B,EAAC;QACzB,EAAE,EAAE,8CAAsC;QAC1C,WAAW,EACT,2HAA2H;KAC9H,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { StartStorageMigrationDto, type StorageMigrationListQuery } from './dto/storage-migration.dto';
2
+ import { StorageMigrationService, type StorageMigrationRunPage, type StorageMigrationRunView } from './storage-migration.service';
3
+ /**
4
+ * The `/api/admin/storage/migrations` routes (`storage_config:read|write`): start, list, read and cancel a copy-only provider migration.
5
+ *
6
+ * @internal
7
+ *
8
+ * @stability experimental
9
+ */
10
+ export declare class StorageMigrationController {
11
+ private readonly migrations;
12
+ constructor(migrations: StorageMigrationService);
13
+ start(dto: StartStorageMigrationDto, userId: string): Promise<{
14
+ data: StorageMigrationRunView;
15
+ }>;
16
+ list(query: StorageMigrationListQuery): Promise<{
17
+ data: StorageMigrationRunPage;
18
+ }>;
19
+ get(runId: string): Promise<{
20
+ data: StorageMigrationRunView;
21
+ }>;
22
+ cancel(runId: string, userId: string): Promise<{
23
+ data: StorageMigrationRunView;
24
+ }>;
25
+ }
26
+ //# sourceMappingURL=storage-migration.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-migration.controller.d.ts","sourceRoot":"","sources":["../../../src/storage/migration/storage-migration.controller.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,wBAAwB,EAIxB,KAAK,yBAAyB,EAC/B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,uBAAuB,EAAE,KAAK,uBAAuB,EAAE,KAAK,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAYlI;;;;;;GAMG;AACH,qBAEa,0BAA0B;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,uBAAuB;IAkB1D,KAAK,CACD,GAAG,EAAE,wBAAwB,EAClB,MAAM,EAAE,MAAM,GAChC,OAAO,CAAC;QAAE,IAAI,EAAE,uBAAuB,CAAA;KAAE,CAAC;IAavC,IAAI,CACuD,KAAK,EAAE,yBAAyB,GAC9F,OAAO,CAAC;QAAE,IAAI,EAAE,uBAAuB,CAAA;KAAE,CAAC;IAavC,GAAG,CAAgC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,uBAAuB,CAAA;KAAE,CAAC;IAkB7F,MAAM,CACqB,KAAK,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,GAChC,OAAO,CAAC;QAAE,IAAI,EAAE,uBAAuB,CAAA;KAAE,CAAC;CAG9C"}
@@ -0,0 +1,135 @@
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.StorageMigrationController = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const swagger_1 = require("@nestjs/swagger");
18
+ const nestjs_zod_1 = require("nestjs-zod");
19
+ const index_1 = require("../../identity/index");
20
+ const storage_constants_1 = require("../storage.constants");
21
+ const storage_migration_dto_1 = require("./dto/storage-migration.dto");
22
+ const storage_migration_service_1 = require("./storage-migration.service");
23
+ // =============================================================================
24
+ // /api/admin/storage/migrations — copy-only storage provider migration (#1093)
25
+ // =============================================================================
26
+ //
27
+ // The same permission pair as `/api/admin/storage-config` (`storage_config:*`):
28
+ // a migration decides where the deployment's bytes live, exactly the authority
29
+ // the configuration screen already grants. Starting and cancelling write;
30
+ // listing and reading read.
31
+ // =============================================================================
32
+ /**
33
+ * The `/api/admin/storage/migrations` routes (`storage_config:read|write`): start, list, read and cancel a copy-only provider migration.
34
+ *
35
+ * @internal
36
+ *
37
+ * @stability experimental
38
+ */
39
+ let StorageMigrationController = class StorageMigrationController {
40
+ migrations;
41
+ constructor(migrations) {
42
+ this.migrations = migrations;
43
+ }
44
+ async start(dto, userId) {
45
+ return { data: await this.migrations.start(dto, userId) };
46
+ }
47
+ async list(query) {
48
+ return { data: await this.migrations.list(query) };
49
+ }
50
+ async get(runId) {
51
+ return { data: await this.migrations.get(runId) };
52
+ }
53
+ async cancel(runId, userId) {
54
+ return { data: await this.migrations.cancel(runId, userId) };
55
+ }
56
+ };
57
+ exports.StorageMigrationController = StorageMigrationController;
58
+ __decorate([
59
+ (0, common_1.Post)(),
60
+ (0, index_1.Auth)({ permissions: [storage_constants_1.PERMISSIONS.STORAGE_CONFIG_WRITE] }),
61
+ (0, common_1.HttpCode)(common_1.HttpStatus.CREATED),
62
+ (0, swagger_1.ApiOperation)({
63
+ summary: 'Start a copy-only storage provider migration (Admin only)',
64
+ description: 'Copies every `ready` object recorded on `sourceProvider` to `targetProvider`, one queue job per ' +
65
+ 'object: the bytes are streamed (never buffered), verified by reading them back (byte count and ' +
66
+ 'sha256), and only then is the row repointed. **The source object is never deleted**; it stays as a ' +
67
+ 'fallback. Returns at once; poll `GET /api/admin/storage/migrations/:runId` for progress.\n\n' +
68
+ 'Both drivers must be registered and configured, and must not name the same bucket (`400`, ' +
69
+ '`details.reason`). **One run at a time**: `409` with the active run at `details.activeRunId`.',
70
+ }),
71
+ (0, swagger_1.ApiResponse)({ status: 201, description: 'The run was started', type: storage_migration_dto_1.StorageMigrationRunDto }),
72
+ (0, swagger_1.ApiResponse)({ status: 400, description: 'Validation error, an unknown or unconfigured driver, or the same bucket on both sides' }),
73
+ (0, swagger_1.ApiResponse)({ status: 409, description: 'A run is already pending or running (`details.activeRunId`)' }),
74
+ __param(0, (0, common_1.Body)()),
75
+ __param(1, (0, index_1.CurrentUser)('id')),
76
+ __metadata("design:type", Function),
77
+ __metadata("design:paramtypes", [storage_migration_dto_1.StartStorageMigrationDto, String]),
78
+ __metadata("design:returntype", Promise)
79
+ ], StorageMigrationController.prototype, "start", null);
80
+ __decorate([
81
+ (0, common_1.Get)(),
82
+ (0, index_1.Auth)({ permissions: [storage_constants_1.PERMISSIONS.STORAGE_CONFIG_READ] }),
83
+ (0, swagger_1.ApiOperation)({
84
+ summary: 'List storage provider migrations (Admin only)',
85
+ description: 'Runs newest first. The counts are recomputed from the runs\' items on every read.',
86
+ }),
87
+ (0, swagger_1.ApiQuery)({ name: 'page', required: false, type: Number, description: 'Page number (default: 1)' }),
88
+ (0, swagger_1.ApiQuery)({ name: 'pageSize', required: false, type: Number, description: 'Runs per page (default: 20, max: 100)' }),
89
+ (0, swagger_1.ApiResponse)({ status: 200, description: 'One page of runs', type: storage_migration_dto_1.StorageMigrationRunListDto }),
90
+ __param(0, (0, common_1.Query)(new nestjs_zod_1.ZodValidationPipe(storage_migration_dto_1.storageMigrationListQuerySchema))),
91
+ __metadata("design:type", Function),
92
+ __metadata("design:paramtypes", [Object]),
93
+ __metadata("design:returntype", Promise)
94
+ ], StorageMigrationController.prototype, "list", null);
95
+ __decorate([
96
+ (0, common_1.Get)(':runId'),
97
+ (0, index_1.Auth)({ permissions: [storage_constants_1.PERMISSIONS.STORAGE_CONFIG_READ] }),
98
+ (0, swagger_1.ApiOperation)({
99
+ summary: 'Get a storage provider migration (Admin only)',
100
+ description: 'One run with live counts: total, migrated, failed, skipped and pending (queued or being copied).',
101
+ }),
102
+ (0, swagger_1.ApiParam)({ name: 'runId', type: String, format: 'uuid' }),
103
+ (0, swagger_1.ApiResponse)({ status: 200, description: 'The run', type: storage_migration_dto_1.StorageMigrationRunDto }),
104
+ (0, swagger_1.ApiResponse)({ status: 404, description: 'No such run' }),
105
+ __param(0, (0, common_1.Param)('runId', common_1.ParseUUIDPipe)),
106
+ __metadata("design:type", Function),
107
+ __metadata("design:paramtypes", [String]),
108
+ __metadata("design:returntype", Promise)
109
+ ], StorageMigrationController.prototype, "get", null);
110
+ __decorate([
111
+ (0, common_1.Post)(':runId/cancel'),
112
+ (0, index_1.Auth)({ permissions: [storage_constants_1.PERMISSIONS.STORAGE_CONFIG_WRITE] }),
113
+ (0, common_1.HttpCode)(common_1.HttpStatus.OK),
114
+ (0, swagger_1.ApiOperation)({
115
+ summary: 'Cancel a storage provider migration (Admin only)',
116
+ description: 'Stops a pending or running run before its next unclaimed object: queued objects are marked ' +
117
+ '`skipped` at once. An object being copied at that moment finishes (its copy is verified). ' +
118
+ 'Objects already repointed stay on the target, and every source object is untouched.',
119
+ }),
120
+ (0, swagger_1.ApiParam)({ name: 'runId', type: String, format: 'uuid' }),
121
+ (0, swagger_1.ApiResponse)({ status: 200, description: 'The cancelled run', type: storage_migration_dto_1.StorageMigrationRunDto }),
122
+ (0, swagger_1.ApiResponse)({ status: 404, description: 'No such run' }),
123
+ (0, swagger_1.ApiResponse)({ status: 409, description: 'The run already finished' }),
124
+ __param(0, (0, common_1.Param)('runId', common_1.ParseUUIDPipe)),
125
+ __param(1, (0, index_1.CurrentUser)('id')),
126
+ __metadata("design:type", Function),
127
+ __metadata("design:paramtypes", [String, String]),
128
+ __metadata("design:returntype", Promise)
129
+ ], StorageMigrationController.prototype, "cancel", null);
130
+ exports.StorageMigrationController = StorageMigrationController = __decorate([
131
+ (0, swagger_1.ApiTags)('Storage Configuration'),
132
+ (0, common_1.Controller)('admin/storage/migrations'),
133
+ __metadata("design:paramtypes", [storage_migration_service_1.StorageMigrationService])
134
+ ], StorageMigrationController);
135
+ //# sourceMappingURL=storage-migration.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-migration.controller.js","sourceRoot":"","sources":["../../../src/storage/migration/storage-migration.controller.ts"],"names":[],"mappings":"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"}