@better-media/framework 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +82 -83
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +82 -83
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -46,4 +46,4 @@ console.log("Uploaded file key:", result.fileKey);
|
|
|
46
46
|
|
|
47
47
|
## Documentation
|
|
48
48
|
|
|
49
|
-
Full documentation is available at [better-media.
|
|
49
|
+
Full documentation is available at [better-media-platform.vercel.app](https://better-media-platform.vercel.app/).
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var core = require('@better-media/core');
|
|
4
3
|
var fs2 = require('fs/promises');
|
|
5
4
|
var crypto = require('crypto');
|
|
6
5
|
var adapterJobs = require('@better-media/adapter-jobs');
|
|
7
|
-
var
|
|
6
|
+
var core = require('@better-media/core');
|
|
7
|
+
var path2 = require('path');
|
|
8
8
|
var fs = require('fs');
|
|
9
9
|
var os = require('os');
|
|
10
10
|
var stream = require('stream');
|
|
@@ -12,25 +12,10 @@ var stream = require('stream');
|
|
|
12
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
13
|
|
|
14
14
|
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
15
|
-
var
|
|
15
|
+
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
16
16
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
20
|
-
var __esm = (fn, res) => function __init() {
|
|
21
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
22
|
-
};
|
|
23
|
-
var __export = (target, all) => {
|
|
24
|
-
for (var name in all)
|
|
25
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// src/core/lifecycle-engine.ts
|
|
29
|
-
var lifecycle_engine_exports = {};
|
|
30
|
-
__export(lifecycle_engine_exports, {
|
|
31
|
-
LifecycleEngine: () => LifecycleEngine,
|
|
32
|
-
createSecureContext: () => createSecureContext
|
|
33
|
-
});
|
|
18
|
+
// src/index.ts
|
|
34
19
|
function createSecureContext(context, pluginName, namespace, trustLevel, capabilities) {
|
|
35
20
|
const api = {
|
|
36
21
|
emitMetadata(patch) {
|
|
@@ -127,52 +112,48 @@ function createSecureContext(context, pluginName, namespace, trustLevel, capabil
|
|
|
127
112
|
});
|
|
128
113
|
return { proxy, api };
|
|
129
114
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (result.valid === false) return result;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
for (const { name, manifest } of backgroundHandlers) {
|
|
157
|
-
const payload = {
|
|
158
|
-
recordId: context.recordId,
|
|
159
|
-
metadata: JSON.parse(JSON.stringify(context.metadata)),
|
|
160
|
-
file: JSON.parse(JSON.stringify(context.file)),
|
|
161
|
-
storageLocation: JSON.parse(JSON.stringify(context.storageLocation)),
|
|
162
|
-
processing: JSON.parse(JSON.stringify(context.processing)),
|
|
163
|
-
hookName,
|
|
164
|
-
pluginName: name,
|
|
165
|
-
manifest: JSON.parse(JSON.stringify(manifest))
|
|
166
|
-
};
|
|
167
|
-
await this.jobAdapter.enqueue(JOB_QUEUE_NAME, payload);
|
|
168
|
-
}
|
|
115
|
+
|
|
116
|
+
// src/core/lifecycle-engine.ts
|
|
117
|
+
var JOB_QUEUE_NAME = "better-media:background";
|
|
118
|
+
var LifecycleEngine = class {
|
|
119
|
+
constructor(registry, jobAdapter) {
|
|
120
|
+
this.registry = registry;
|
|
121
|
+
this.jobAdapter = jobAdapter;
|
|
122
|
+
}
|
|
123
|
+
async trigger(hookName, context) {
|
|
124
|
+
const handlers = this.registry.get(hookName) ?? [];
|
|
125
|
+
const syncHandlers = handlers.filter((h) => h.mode === "sync");
|
|
126
|
+
const backgroundHandlers = handlers.filter((h) => h.mode === "background");
|
|
127
|
+
for (const { name, fn, manifest } of syncHandlers) {
|
|
128
|
+
const { proxy, api } = createSecureContext(
|
|
129
|
+
context,
|
|
130
|
+
name,
|
|
131
|
+
manifest.namespace,
|
|
132
|
+
manifest.trustLevel,
|
|
133
|
+
manifest.capabilities
|
|
134
|
+
);
|
|
135
|
+
const result = await fn(proxy, api);
|
|
136
|
+
if (result !== void 0 && typeof result === "object" && "valid" in result) {
|
|
137
|
+
if (result.valid === false) return result;
|
|
169
138
|
}
|
|
170
|
-
}
|
|
139
|
+
}
|
|
140
|
+
for (const { name, manifest } of backgroundHandlers) {
|
|
141
|
+
const payload = {
|
|
142
|
+
recordId: context.recordId,
|
|
143
|
+
metadata: JSON.parse(JSON.stringify(context.metadata)),
|
|
144
|
+
file: JSON.parse(JSON.stringify(context.file)),
|
|
145
|
+
storageLocation: JSON.parse(JSON.stringify(context.storageLocation)),
|
|
146
|
+
processing: JSON.parse(JSON.stringify(context.processing)),
|
|
147
|
+
hookName,
|
|
148
|
+
pluginName: name,
|
|
149
|
+
manifest: JSON.parse(JSON.stringify(manifest))
|
|
150
|
+
};
|
|
151
|
+
await this.jobAdapter.enqueue(JOB_QUEUE_NAME, payload);
|
|
152
|
+
}
|
|
171
153
|
}
|
|
172
|
-
}
|
|
154
|
+
};
|
|
173
155
|
|
|
174
156
|
// src/plugins/plugin-registry.ts
|
|
175
|
-
init_lifecycle_engine();
|
|
176
157
|
function createEmptyRegistry() {
|
|
177
158
|
const reg = /* @__PURE__ */ new Map();
|
|
178
159
|
for (const name of core.HOOK_NAMES) {
|
|
@@ -336,9 +317,6 @@ function hasBackgroundHandlers(registry) {
|
|
|
336
317
|
}
|
|
337
318
|
return false;
|
|
338
319
|
}
|
|
339
|
-
|
|
340
|
-
// src/index.ts
|
|
341
|
-
init_lifecycle_engine();
|
|
342
320
|
async function loadTrustedFromDb(database, recordId) {
|
|
343
321
|
const record = await database.findOne({
|
|
344
322
|
model: "media",
|
|
@@ -407,8 +385,8 @@ async function saveTrustedToDb(database, recordId, fileKey, trusted, initialArgs
|
|
|
407
385
|
}
|
|
408
386
|
}
|
|
409
387
|
async function streamToTempFile(stream$1, fileKey) {
|
|
410
|
-
const ext =
|
|
411
|
-
const tmpPath =
|
|
388
|
+
const ext = path2__default.default.extname(fileKey) || ".bin";
|
|
389
|
+
const tmpPath = path2__default.default.join(os__default.default.tmpdir(), `better-media-${crypto.randomUUID()}${ext}`);
|
|
412
390
|
const nodeStream = stream$1 instanceof stream.Readable ? stream$1 : stream.Readable.fromWeb(stream$1);
|
|
413
391
|
const writeStream = fs.createWriteStream(tmpPath);
|
|
414
392
|
await new Promise((resolve, reject) => {
|
|
@@ -426,6 +404,10 @@ async function loadFileIntoContext(context, fileHandling) {
|
|
|
426
404
|
const storageWithExtras = storage;
|
|
427
405
|
if (!context.utilities) context.utilities = {};
|
|
428
406
|
const fileContent = {};
|
|
407
|
+
if (context.storageLocation.url && context.storageLocation.url === context.file.key) {
|
|
408
|
+
context.utilities.fileContent = fileContent;
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
429
411
|
let useStream = false;
|
|
430
412
|
if (maxBufferBytes != null && typeof storageWithExtras.getSize === "function" && typeof storageWithExtras.getStream === "function") {
|
|
431
413
|
const size = await storageWithExtras.getSize(fileKey);
|
|
@@ -466,8 +448,22 @@ async function cleanupTempFile(context) {
|
|
|
466
448
|
function buildFileInfo(fileKey, metadata) {
|
|
467
449
|
const mime = metadata.contentType ?? metadata.mimeType ?? metadata["content-type"];
|
|
468
450
|
const size = typeof metadata.size === "number" ? metadata.size : void 0;
|
|
469
|
-
const originalName = metadata.originalName ?? metadata.originalname
|
|
470
|
-
|
|
451
|
+
const originalName = metadata.originalName ?? metadata.originalname ?? (() => {
|
|
452
|
+
try {
|
|
453
|
+
const url = new URL(fileKey);
|
|
454
|
+
return path2__default.default.basename(url.pathname);
|
|
455
|
+
} catch {
|
|
456
|
+
return void 0;
|
|
457
|
+
}
|
|
458
|
+
})();
|
|
459
|
+
const ext = originalName ? path2__default.default.extname(originalName).toLowerCase() : (() => {
|
|
460
|
+
try {
|
|
461
|
+
const url = new URL(fileKey);
|
|
462
|
+
return path2__default.default.extname(url.pathname).toLowerCase();
|
|
463
|
+
} catch {
|
|
464
|
+
return path2__default.default.extname(fileKey).toLowerCase();
|
|
465
|
+
}
|
|
466
|
+
})();
|
|
471
467
|
return {
|
|
472
468
|
key: fileKey,
|
|
473
469
|
size,
|
|
@@ -477,12 +473,12 @@ function buildFileInfo(fileKey, metadata) {
|
|
|
477
473
|
checksums: void 0
|
|
478
474
|
};
|
|
479
475
|
}
|
|
480
|
-
function buildStorageLocation(fileKey) {
|
|
476
|
+
function buildStorageLocation(fileKey, referenceUrl) {
|
|
481
477
|
return {
|
|
482
478
|
key: fileKey,
|
|
483
479
|
bucket: void 0,
|
|
484
480
|
region: void 0,
|
|
485
|
-
url:
|
|
481
|
+
url: referenceUrl
|
|
486
482
|
};
|
|
487
483
|
}
|
|
488
484
|
function syncTrustedToFile(context) {
|
|
@@ -515,7 +511,7 @@ var PipelineExecutor = class {
|
|
|
515
511
|
const context = {
|
|
516
512
|
recordId,
|
|
517
513
|
file: buildFileInfo(fileKey, meta),
|
|
518
|
-
storageLocation: buildStorageLocation(fileKey),
|
|
514
|
+
storageLocation: buildStorageLocation(fileKey, appContext.referenceUrl),
|
|
519
515
|
processing: {},
|
|
520
516
|
metadata: { ...meta, ...appContext },
|
|
521
517
|
// Merge for plugins to read backwards-compatibly
|
|
@@ -580,7 +576,7 @@ async function runBackgroundJob(payload, registry, storage, database, jobs, file
|
|
|
580
576
|
size: typeof meta.size === "number" ? meta.size : void 0,
|
|
581
577
|
mimeType: typeof (meta.contentType ?? meta.mimeType ?? meta["content-type"]) === "string" ? meta.contentType ?? meta.mimeType ?? meta["content-type"] : void 0,
|
|
582
578
|
originalName: typeof (meta.originalName ?? meta.originalname) === "string" ? meta.originalName ?? meta.originalname : void 0,
|
|
583
|
-
extension:
|
|
579
|
+
extension: path2__default.default.extname(legacyKey).toLowerCase() || void 0
|
|
584
580
|
} : { key: "" });
|
|
585
581
|
const recordId = payloadRecordId ?? file.key ?? "unknown";
|
|
586
582
|
const storageLocation = payloadStorage ?? { key: file.key };
|
|
@@ -609,8 +605,7 @@ async function runBackgroundJob(payload, registry, storage, database, jobs, file
|
|
|
609
605
|
throw new Error(`Handler not found: ${hookName}/${pluginName}`);
|
|
610
606
|
}
|
|
611
607
|
const manifest = handler.manifest;
|
|
612
|
-
const {
|
|
613
|
-
const { proxy, api } = createSecureContext2(
|
|
608
|
+
const { proxy, api } = createSecureContext(
|
|
614
609
|
context,
|
|
615
610
|
pluginName,
|
|
616
611
|
manifest.namespace,
|
|
@@ -912,7 +907,7 @@ async function normalizeInput(input, fileHandling) {
|
|
|
912
907
|
data = Buffer.concat(chunks);
|
|
913
908
|
} else if ("url" in file && file.url) {
|
|
914
909
|
if (file.mode === "reference") {
|
|
915
|
-
|
|
910
|
+
return { metadata, shouldDeleteSource: false, isReference: true, referenceUrl: file.url };
|
|
916
911
|
}
|
|
917
912
|
const response = await fetch(file.url);
|
|
918
913
|
if (!response.ok) throw new Error(`Failed to fetch URL: ${response.statusText}`);
|
|
@@ -948,15 +943,19 @@ function createBetterMedia(config) {
|
|
|
948
943
|
async ingest(input) {
|
|
949
944
|
const normalized = await normalizeInput(input, fileHandling);
|
|
950
945
|
const recordId = crypto.randomUUID();
|
|
951
|
-
const finalKey = input.key ?? normalized.metadata.filename ?? recordId;
|
|
946
|
+
const finalKey = input.key ?? normalized.metadata.filename ?? (normalized.isReference ? normalized.referenceUrl : void 0) ?? recordId;
|
|
952
947
|
try {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
finalKey,
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
948
|
+
if (normalized.isReference && normalized.referenceUrl) {
|
|
949
|
+
normalized.metadata.referenceUrl = normalized.referenceUrl;
|
|
950
|
+
} else if (normalized.data) {
|
|
951
|
+
await storage.put(finalKey, normalized.data);
|
|
952
|
+
} else {
|
|
953
|
+
throw new Error("Ingest failed: No data and not a reference.");
|
|
954
|
+
}
|
|
955
|
+
await runPipeline(recordId, finalKey, normalized.metadata, {
|
|
956
|
+
...normalized.metadata.context ?? {},
|
|
957
|
+
referenceUrl: normalized.referenceUrl
|
|
958
|
+
});
|
|
960
959
|
return {
|
|
961
960
|
id: recordId,
|
|
962
961
|
key: finalKey,
|