@cogenta/core 0.1.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/dist/cache/entry.d.ts +32 -0
- package/dist/cache/entry.d.ts.map +1 -0
- package/dist/cache/entry.js +72 -0
- package/dist/cache/entry.js.map +1 -0
- package/dist/cache/file.d.ts +16 -0
- package/dist/cache/file.d.ts.map +1 -0
- package/dist/cache/file.js +191 -0
- package/dist/cache/file.js.map +1 -0
- package/dist/cache/index.d.ts +20 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +25 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/memory.d.ts +11 -0
- package/dist/cache/memory.d.ts.map +1 -0
- package/dist/cache/memory.js +89 -0
- package/dist/cache/memory.js.map +1 -0
- package/dist/cache/redis.d.ts +54 -0
- package/dist/cache/redis.d.ts.map +1 -0
- package/dist/cache/redis.js +167 -0
- package/dist/cache/redis.js.map +1 -0
- package/dist/cache/types.d.ts +37 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +2 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/config/define-config.d.ts +19 -0
- package/dist/config/define-config.d.ts.map +1 -0
- package/dist/config/define-config.js +20 -0
- package/dist/config/define-config.js.map +1 -0
- package/dist/config/env.d.ts +30 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +139 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/load-config.d.ts +30 -0
- package/dist/config/load-config.d.ts.map +1 -0
- package/dist/config/load-config.js +83 -0
- package/dist/config/load-config.js.map +1 -0
- package/dist/config/resolve-config.d.ts +14 -0
- package/dist/config/resolve-config.d.ts.map +1 -0
- package/dist/config/resolve-config.js +146 -0
- package/dist/config/resolve-config.js.map +1 -0
- package/dist/config/schema.d.ts +68 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +75 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/types.d.ts +126 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +6 -0
- package/dist/config/types.js.map +1 -0
- package/dist/db/dialect.d.ts +64 -0
- package/dist/db/dialect.d.ts.map +1 -0
- package/dist/db/dialect.js +147 -0
- package/dist/db/dialect.js.map +1 -0
- package/dist/db/drizzle.d.ts +35 -0
- package/dist/db/drizzle.d.ts.map +1 -0
- package/dist/db/drizzle.js +128 -0
- package/dist/db/drizzle.js.map +1 -0
- package/dist/db/index.d.ts +28 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +30 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/mysql.d.ts +39 -0
- package/dist/db/mysql.d.ts.map +1 -0
- package/dist/db/mysql.js +224 -0
- package/dist/db/mysql.js.map +1 -0
- package/dist/db/postgres.d.ts +47 -0
- package/dist/db/postgres.d.ts.map +1 -0
- package/dist/db/postgres.js +174 -0
- package/dist/db/postgres.js.map +1 -0
- package/dist/db/sqlite.d.ts +41 -0
- package/dist/db/sqlite.d.ts.map +1 -0
- package/dist/db/sqlite.js +213 -0
- package/dist/db/sqlite.js.map +1 -0
- package/dist/db/types.d.ts +71 -0
- package/dist/db/types.d.ts.map +1 -0
- package/dist/db/types.js +2 -0
- package/dist/db/types.js.map +1 -0
- package/dist/drivers/index.d.ts +5 -0
- package/dist/drivers/index.d.ts.map +1 -0
- package/dist/drivers/index.js +3 -0
- package/dist/drivers/index.js.map +1 -0
- package/dist/drivers/registry.d.ts +27 -0
- package/dist/drivers/registry.d.ts.map +1 -0
- package/dist/drivers/registry.js +162 -0
- package/dist/drivers/registry.js.map +1 -0
- package/dist/drivers/types.d.ts +59 -0
- package/dist/drivers/types.d.ts.map +1 -0
- package/dist/drivers/types.js +2 -0
- package/dist/drivers/types.js.map +1 -0
- package/dist/errors/codes.d.ts +8 -0
- package/dist/errors/codes.d.ts.map +1 -0
- package/dist/errors/codes.js +201 -0
- package/dist/errors/codes.js.map +1 -0
- package/dist/errors/cogenta-error.d.ts +38 -0
- package/dist/errors/cogenta-error.d.ts.map +1 -0
- package/dist/errors/cogenta-error.js +31 -0
- package/dist/errors/cogenta-error.js.map +1 -0
- package/dist/errors/index.d.ts +5 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +3 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/id.d.ts +5 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +82 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/index.d.ts +5 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +4 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/logger.d.ts +10 -0
- package/dist/logger/logger.d.ts.map +1 -0
- package/dist/logger/logger.js +108 -0
- package/dist/logger/logger.js.map +1 -0
- package/dist/logger/redact.d.ts +12 -0
- package/dist/logger/redact.d.ts.map +1 -0
- package/dist/logger/redact.js +96 -0
- package/dist/logger/redact.js.map +1 -0
- package/dist/logger/types.d.ts +32 -0
- package/dist/logger/types.d.ts.map +1 -0
- package/dist/logger/types.js +3 -0
- package/dist/logger/types.js.map +1 -0
- package/dist/media/format-sniff.d.ts +22 -0
- package/dist/media/format-sniff.d.ts.map +1 -0
- package/dist/media/format-sniff.js +77 -0
- package/dist/media/format-sniff.js.map +1 -0
- package/dist/media/index.d.ts +5 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/index.js +4 -0
- package/dist/media/index.js.map +1 -0
- package/dist/media/store.d.ts +13 -0
- package/dist/media/store.d.ts.map +1 -0
- package/dist/media/store.js +211 -0
- package/dist/media/store.js.map +1 -0
- package/dist/media/types.d.ts +70 -0
- package/dist/media/types.d.ts.map +1 -0
- package/dist/media/types.js +2 -0
- package/dist/media/types.js.map +1 -0
- package/dist/migrations/index.d.ts +4 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +2 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/migrator.d.ts +18 -0
- package/dist/migrations/migrator.d.ts.map +1 -0
- package/dist/migrations/migrator.js +247 -0
- package/dist/migrations/migrator.js.map +1 -0
- package/dist/migrations/types.d.ts +63 -0
- package/dist/migrations/types.d.ts.map +1 -0
- package/dist/migrations/types.js +2 -0
- package/dist/migrations/types.js.map +1 -0
- package/dist/queue/bullmq.d.ts +119 -0
- package/dist/queue/bullmq.d.ts.map +1 -0
- package/dist/queue/bullmq.js +391 -0
- package/dist/queue/bullmq.js.map +1 -0
- package/dist/queue/database.d.ts +17 -0
- package/dist/queue/database.d.ts.map +1 -0
- package/dist/queue/database.js +242 -0
- package/dist/queue/database.js.map +1 -0
- package/dist/queue/index.d.ts +7 -0
- package/dist/queue/index.d.ts.map +1 -0
- package/dist/queue/index.js +4 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/queue/types.d.ts +61 -0
- package/dist/queue/types.d.ts.map +1 -0
- package/dist/queue/types.js +2 -0
- package/dist/queue/types.js.map +1 -0
- package/dist/storage/index.d.ts +14 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +17 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/key.d.ts +12 -0
- package/dist/storage/key.d.ts.map +1 -0
- package/dist/storage/key.js +43 -0
- package/dist/storage/key.js.map +1 -0
- package/dist/storage/local.d.ts +23 -0
- package/dist/storage/local.d.ts.map +1 -0
- package/dist/storage/local.js +204 -0
- package/dist/storage/local.js.map +1 -0
- package/dist/storage/s3.d.ts +54 -0
- package/dist/storage/s3.d.ts.map +1 -0
- package/dist/storage/s3.js +240 -0
- package/dist/storage/s3.js.map +1 -0
- package/dist/storage/types.d.ts +45 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/types.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** What replaces a redacted value. Constant so tests and readers can match on it. */
|
|
2
|
+
export const REDACTED = '[redacted]';
|
|
3
|
+
/**
|
|
4
|
+
* Field names whose value is a credential, normalised to lowercase letters and
|
|
5
|
+
* digits so `API_KEY`, `x-api-key` and `apiKey` all collapse to `apikey`.
|
|
6
|
+
*/
|
|
7
|
+
const SECRET_KEYS = new Set([
|
|
8
|
+
'password',
|
|
9
|
+
'passwd',
|
|
10
|
+
'pass',
|
|
11
|
+
'secret',
|
|
12
|
+
'token',
|
|
13
|
+
'apikey',
|
|
14
|
+
'apisecret',
|
|
15
|
+
'accesstoken',
|
|
16
|
+
'refreshtoken',
|
|
17
|
+
'idtoken',
|
|
18
|
+
'bearer',
|
|
19
|
+
'authorization',
|
|
20
|
+
'auth',
|
|
21
|
+
'cookie',
|
|
22
|
+
'setcookie',
|
|
23
|
+
'session',
|
|
24
|
+
'sessionid',
|
|
25
|
+
'credential',
|
|
26
|
+
'credentials',
|
|
27
|
+
'privatekey',
|
|
28
|
+
'clientsecret',
|
|
29
|
+
'accesskey',
|
|
30
|
+
'accesskeyid',
|
|
31
|
+
'secretaccesskey',
|
|
32
|
+
'signature',
|
|
33
|
+
'dsn',
|
|
34
|
+
]);
|
|
35
|
+
/**
|
|
36
|
+
* Suffixes that make a compound name a secret: `llmApiKey`, `s3SecretAccessKey`.
|
|
37
|
+
* Deliberately not `key` on its own — `cacheKey` and `keyCount` are not secrets,
|
|
38
|
+
* and over-redacting makes logs useless, which is its own kind of failure.
|
|
39
|
+
*/
|
|
40
|
+
const SECRET_SUFFIXES = ['password', 'passwd', 'secret', 'apikey', 'accesstoken', 'refreshtoken'];
|
|
41
|
+
/** Values that are credentials whatever the field is called. */
|
|
42
|
+
const SECRET_VALUES = [
|
|
43
|
+
/sk-ant-[a-zA-Z0-9_-]{20,}/,
|
|
44
|
+
/\bsk-(proj-)?[a-zA-Z0-9]{32,}/,
|
|
45
|
+
/\b(AKIA|ASIA)[0-9A-Z]{16}\b/,
|
|
46
|
+
/\bgh[pousr]_[A-Za-z0-9]{30,}/,
|
|
47
|
+
/-----BEGIN (RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/,
|
|
48
|
+
/\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\./,
|
|
49
|
+
/\bxox[abprs]-[A-Za-z0-9-]{10,}/,
|
|
50
|
+
];
|
|
51
|
+
/** Matches `<scheme>://<user>:<password>@<host>`, capturing the password alone. */
|
|
52
|
+
const URL_CREDENTIALS = /^([a-z][a-z0-9+.-]*:\/\/[^:@\s/]+:)([^@\s/]+)(@)/i;
|
|
53
|
+
const MAX_DEPTH = 8;
|
|
54
|
+
function isSecretKey(key) {
|
|
55
|
+
const normalised = key.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
56
|
+
if (SECRET_KEYS.has(normalised))
|
|
57
|
+
return true;
|
|
58
|
+
return SECRET_SUFFIXES.some((suffix) => normalised.endsWith(suffix));
|
|
59
|
+
}
|
|
60
|
+
function redactString(value) {
|
|
61
|
+
if (SECRET_VALUES.some((pattern) => pattern.test(value)))
|
|
62
|
+
return REDACTED;
|
|
63
|
+
return value.replace(URL_CREDENTIALS, `$1${REDACTED}$3`);
|
|
64
|
+
}
|
|
65
|
+
function redactValue(value, depth, seen) {
|
|
66
|
+
if (typeof value === 'string')
|
|
67
|
+
return redactString(value);
|
|
68
|
+
if (value === null || typeof value !== 'object')
|
|
69
|
+
return value;
|
|
70
|
+
if (depth >= MAX_DEPTH)
|
|
71
|
+
return '[depth limit]';
|
|
72
|
+
if (seen.has(value))
|
|
73
|
+
return '[circular]';
|
|
74
|
+
seen.add(value);
|
|
75
|
+
if (Array.isArray(value))
|
|
76
|
+
return value.map((item) => redactValue(item, depth + 1, seen));
|
|
77
|
+
if (value instanceof Date)
|
|
78
|
+
return value.toISOString();
|
|
79
|
+
const output = {};
|
|
80
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
81
|
+
output[key] = isSecretKey(key) ? REDACTED : redactValue(entry, depth + 1, seen);
|
|
82
|
+
}
|
|
83
|
+
return output;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Returns a copy of `fields` with credentials removed — by field name, by value
|
|
87
|
+
* shape, and inside connection strings.
|
|
88
|
+
*
|
|
89
|
+
* This is belt and braces on top of rule R7: secrets are not supposed to reach a
|
|
90
|
+
* log call in the first place. Defence in depth is warranted because a leaked
|
|
91
|
+
* key in a log file is discovered late, by someone else, and costs a rotation.
|
|
92
|
+
*/
|
|
93
|
+
export function redact(fields) {
|
|
94
|
+
return redactValue(fields, 0, new WeakSet());
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/logger/redact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Ordered from most to least verbose. `silent` emits nothing at all. */
|
|
2
|
+
export declare const LOG_LEVELS: readonly ['debug', 'info', 'warn', 'error', 'silent'];
|
|
3
|
+
export type LogLevel = (typeof LOG_LEVELS)[number];
|
|
4
|
+
/** Emitted levels only — `silent` is a threshold, never a record's level. */
|
|
5
|
+
export type EmittedLogLevel = Exclude<LogLevel, 'silent'>;
|
|
6
|
+
export type LogFields = Record<string, unknown>;
|
|
7
|
+
/** One emitted line, as NDJSON. Structured; never a formatted sentence. */
|
|
8
|
+
export interface LogRecord extends LogFields {
|
|
9
|
+
readonly time: string;
|
|
10
|
+
readonly level: EmittedLogLevel;
|
|
11
|
+
readonly msg: string;
|
|
12
|
+
}
|
|
13
|
+
/** Where a line goes. Injected, so tests capture instead of writing to stdout. */
|
|
14
|
+
export type LogDestination = (line: string) => void;
|
|
15
|
+
export interface Logger {
|
|
16
|
+
readonly level: LogLevel;
|
|
17
|
+
debug(message: string, fields?: LogFields): void;
|
|
18
|
+
info(message: string, fields?: LogFields): void;
|
|
19
|
+
warn(message: string, fields?: LogFields): void;
|
|
20
|
+
error(message: string, fields?: LogFields): void;
|
|
21
|
+
/** A logger that repeats `bindings` on every record. Never mutates its parent. */
|
|
22
|
+
child(bindings: LogFields): Logger;
|
|
23
|
+
isLevelEnabled(level: LogLevel): boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface LoggerOptions {
|
|
26
|
+
readonly level?: LogLevel;
|
|
27
|
+
readonly destination?: LogDestination;
|
|
28
|
+
/** Injected so tests get stable timestamps. */
|
|
29
|
+
readonly clock?: () => Date;
|
|
30
|
+
readonly bindings?: LogFields;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/logger/types.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,eAAO,MAAM,UAAU,YAAI,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAA;AAE/E,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AAElD,6EAA6E;AAC7E,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;AAEzD,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE/C,2EAA2E;AAC3E,MAAM,WAAW,SAAU,SAAQ,SAAS;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED,kFAAkF;AAClF,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;AAEnD,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;IACxB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;IAChD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;IAC/C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;IAC/C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;IAChD,kFAAkF;IAClF,KAAK,CAAC,QAAQ,EAAE,SAAS,GAAG,MAAM,CAAA;IAClC,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAA;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,cAAc,CAAA;IACrC,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,IAAI,CAAA;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/logger/types.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container sniffing, shared by the image pipeline (`@cogenta/render`) and
|
|
3
|
+
* the media upload route (`@cogenta/api`) — moved here, rather than
|
|
4
|
+
* duplicated or pulled in by depending on `@cogenta/render`, because
|
|
5
|
+
* `@cogenta/render` already depends on `@cogenta/core` and an upload route
|
|
6
|
+
* has no reason to pull in the render package's Astro/sharp integration just
|
|
7
|
+
* for four byte-signature checks.
|
|
8
|
+
*
|
|
9
|
+
* The format is read from the magic bytes, never from a filename or an
|
|
10
|
+
* uploaded `Content-Type` — both are attacker-controlled, and "upload a
|
|
11
|
+
* disguised file" is a named security test for the media library
|
|
12
|
+
* (L2-admin.md).
|
|
13
|
+
*/
|
|
14
|
+
export type SniffedImageFormat = 'avif' | 'webp' | 'jpeg' | 'png';
|
|
15
|
+
/** The format, or `null` when this is not something the pipeline can decode. */
|
|
16
|
+
export declare function sniffImageFormat(bytes: Uint8Array): SniffedImageFormat | null;
|
|
17
|
+
/**
|
|
18
|
+
* A human name for bytes that were refused. Never echoes the bytes back: an
|
|
19
|
+
* error message is a place a payload can travel to.
|
|
20
|
+
*/
|
|
21
|
+
export declare function describeContainer(bytes: Uint8Array): string;
|
|
22
|
+
//# sourceMappingURL=format-sniff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-sniff.d.ts","sourceRoot":"","sources":["../../src/media/format-sniff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;AA2BjE,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,kBAAkB,GAAG,IAAI,CAQ7E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAc3D"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container sniffing, shared by the image pipeline (`@cogenta/render`) and
|
|
3
|
+
* the media upload route (`@cogenta/api`) — moved here, rather than
|
|
4
|
+
* duplicated or pulled in by depending on `@cogenta/render`, because
|
|
5
|
+
* `@cogenta/render` already depends on `@cogenta/core` and an upload route
|
|
6
|
+
* has no reason to pull in the render package's Astro/sharp integration just
|
|
7
|
+
* for four byte-signature checks.
|
|
8
|
+
*
|
|
9
|
+
* The format is read from the magic bytes, never from a filename or an
|
|
10
|
+
* uploaded `Content-Type` — both are attacker-controlled, and "upload a
|
|
11
|
+
* disguised file" is a named security test for the media library
|
|
12
|
+
* (L2-admin.md).
|
|
13
|
+
*/
|
|
14
|
+
function starts(bytes, offset, ascii) {
|
|
15
|
+
if (bytes.length < offset + ascii.length)
|
|
16
|
+
return false;
|
|
17
|
+
for (let index = 0; index < ascii.length; index += 1) {
|
|
18
|
+
if (bytes[offset + index] !== ascii.charCodeAt(index))
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
function startsWithBytes(bytes, signature) {
|
|
24
|
+
if (bytes.length < signature.length)
|
|
25
|
+
return false;
|
|
26
|
+
return signature.every((byte, index) => bytes[index] === byte);
|
|
27
|
+
}
|
|
28
|
+
const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
|
|
29
|
+
const JPEG_SIGNATURE = [0xff, 0xd8, 0xff];
|
|
30
|
+
/** ISO base media brands that are AVIF, and the ones that are its HEIF cousins. */
|
|
31
|
+
const AVIF_BRANDS = new Set(['avif', 'avis']);
|
|
32
|
+
const HEIF_BRANDS = new Set(['heic', 'heix', 'hevc', 'hevx', 'mif1', 'msf1']);
|
|
33
|
+
function brandOf(bytes) {
|
|
34
|
+
if (!starts(bytes, 4, 'ftyp') || bytes.length < 12)
|
|
35
|
+
return null;
|
|
36
|
+
return String.fromCharCode(bytes[8] ?? 0, bytes[9] ?? 0, bytes[10] ?? 0, bytes[11] ?? 0);
|
|
37
|
+
}
|
|
38
|
+
/** The format, or `null` when this is not something the pipeline can decode. */
|
|
39
|
+
export function sniffImageFormat(bytes) {
|
|
40
|
+
if (startsWithBytes(bytes, PNG_SIGNATURE))
|
|
41
|
+
return 'png';
|
|
42
|
+
if (startsWithBytes(bytes, JPEG_SIGNATURE))
|
|
43
|
+
return 'jpeg';
|
|
44
|
+
if (starts(bytes, 0, 'RIFF') && starts(bytes, 8, 'WEBP'))
|
|
45
|
+
return 'webp';
|
|
46
|
+
const brand = brandOf(bytes);
|
|
47
|
+
if (brand !== null && AVIF_BRANDS.has(brand))
|
|
48
|
+
return 'avif';
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A human name for bytes that were refused. Never echoes the bytes back: an
|
|
53
|
+
* error message is a place a payload can travel to.
|
|
54
|
+
*/
|
|
55
|
+
export function describeContainer(bytes) {
|
|
56
|
+
if (bytes.length === 0)
|
|
57
|
+
return 'an empty file';
|
|
58
|
+
if (starts(bytes, 0, 'GIF8'))
|
|
59
|
+
return 'a GIF';
|
|
60
|
+
if (starts(bytes, 0, 'BM'))
|
|
61
|
+
return 'a BMP';
|
|
62
|
+
if (startsWithBytes(bytes, [0x49, 0x49, 0x2a, 0x00]))
|
|
63
|
+
return 'a TIFF';
|
|
64
|
+
if (startsWithBytes(bytes, [0x4d, 0x4d, 0x00, 0x2a]))
|
|
65
|
+
return 'a TIFF';
|
|
66
|
+
if (starts(bytes, 0, '<svg') || starts(bytes, 0, '<?xml'))
|
|
67
|
+
return 'an SVG';
|
|
68
|
+
if (startsWithBytes(bytes, [0x25, 0x50, 0x44, 0x46]))
|
|
69
|
+
return 'a PDF';
|
|
70
|
+
const brand = brandOf(bytes);
|
|
71
|
+
if (brand !== null && HEIF_BRANDS.has(brand))
|
|
72
|
+
return 'a HEIF image';
|
|
73
|
+
if (brand !== null)
|
|
74
|
+
return `an ISO media file (brand "${brand}")`;
|
|
75
|
+
return 'not a recognised image';
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=format-sniff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-sniff.js","sourceRoot":"","sources":["../../src/media/format-sniff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { describeContainer, type SniffedImageFormat, sniffImageFormat } from './format-sniff.js';
|
|
2
|
+
export { createDatabaseMediaStore, type DatabaseMediaStoreOptions } from './store.js';
|
|
3
|
+
export type { CreateMediaInput, FocalPoint, ListMediaOptions, MediaAsset, MediaKind, MediaPage, MediaStore, UpdateMediaInput, } from './types.js';
|
|
4
|
+
export { MEDIA_KINDS } from './types.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAChG,OAAO,EAAE,wBAAwB,EAAE,KAAK,yBAAyB,EAAE,MAAM,YAAY,CAAA;AACrF,YAAY,EACV,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,gBAAgB,GACjB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA2B,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAChG,OAAO,EAAE,wBAAwB,EAAkC,MAAM,YAAY,CAAA;AAWrF,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type DatabaseHandle } from '../db/index.js';
|
|
2
|
+
import type { MediaStore } from './types.js';
|
|
3
|
+
export interface DatabaseMediaStoreOptions {
|
|
4
|
+
readonly db: DatabaseHandle;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The media asset store: one SQL table, played against SQLite, Postgres and
|
|
8
|
+
* MySQL by the same contract — the same shape as the degraded job queue
|
|
9
|
+
* (`../queue/database.ts`), since a media library has no infrastructure
|
|
10
|
+
* dependency to fall back from in the first place (rule R1).
|
|
11
|
+
*/
|
|
12
|
+
export declare function createDatabaseMediaStore(options: DatabaseMediaStoreOptions): MediaStore;
|
|
13
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/media/store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,gBAAgB,CAAA;AAE5E,OAAO,KAAK,EAMV,UAAU,EAEX,MAAM,YAAY,CAAA;AAMnB,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAA;CAC5B;AAuFD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,UAAU,CA4JvF"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { identifier, limit, sql } from '../db/index.js';
|
|
3
|
+
import { CogentaError } from '../errors/index.js';
|
|
4
|
+
const TABLE = 'cogenta_media';
|
|
5
|
+
const DEFAULT_LIMIT = 50;
|
|
6
|
+
const MAX_LIMIT = 200;
|
|
7
|
+
function rowToAsset(row) {
|
|
8
|
+
return {
|
|
9
|
+
id: row.id,
|
|
10
|
+
kind: row.kind,
|
|
11
|
+
filename: row.filename,
|
|
12
|
+
mimeType: row.mime_type,
|
|
13
|
+
size: Number(row.size),
|
|
14
|
+
width: row.width === null ? null : Number(row.width),
|
|
15
|
+
height: row.height === null ? null : Number(row.height),
|
|
16
|
+
alt: row.alt,
|
|
17
|
+
decorative: row.decorative === true || row.decorative === 1,
|
|
18
|
+
decorativeJustification: row.decorative_justification,
|
|
19
|
+
focal: row.focal === null ? null : JSON.parse(row.focal),
|
|
20
|
+
storageKey: row.storage_key,
|
|
21
|
+
createdAt: row.created_at,
|
|
22
|
+
createdBy: row.created_by,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function notFound(id) {
|
|
26
|
+
return new CogentaError({
|
|
27
|
+
code: 'MEDIA_NOT_FOUND',
|
|
28
|
+
message: `No media asset with id "${id}".`,
|
|
29
|
+
hint: 'List media to find a valid id, or the asset may already have been deleted.',
|
|
30
|
+
details: { id },
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A decorative asset carries no description (L2-admin.md's own rule: the
|
|
35
|
+
* decorative checkbox writes `alt=""`), and needs a reason a reviewer can
|
|
36
|
+
* read instead — an editor who cannot explain why an image is decorative is
|
|
37
|
+
* usually one who meant to write alt text and skipped it by accident.
|
|
38
|
+
*/
|
|
39
|
+
function validateAltPolicy(alt, decorative, justification) {
|
|
40
|
+
if (decorative) {
|
|
41
|
+
if (justification === null || justification.trim().length === 0) {
|
|
42
|
+
throw new CogentaError({
|
|
43
|
+
code: 'MEDIA_INVALID',
|
|
44
|
+
message: 'A decorative image needs a justification.',
|
|
45
|
+
hint: 'Say why the image carries no information a screen reader needs to announce.',
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (alt.trim().length === 0) {
|
|
51
|
+
throw new CogentaError({
|
|
52
|
+
code: 'MEDIA_INVALID',
|
|
53
|
+
message: 'Alt text is required unless the image is marked decorative.',
|
|
54
|
+
hint: 'Describe what the image shows, or mark it decorative with a justification.',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function encodeCursor(row) {
|
|
59
|
+
return Buffer.from(`${row.createdAt}|${row.id}`, 'utf8').toString('base64url');
|
|
60
|
+
}
|
|
61
|
+
function decodeCursor(cursor) {
|
|
62
|
+
try {
|
|
63
|
+
const [createdAt, id] = Buffer.from(cursor, 'base64url').toString('utf8').split('|');
|
|
64
|
+
if (createdAt === undefined || id === undefined)
|
|
65
|
+
return null;
|
|
66
|
+
return { createdAt, id };
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The media asset store: one SQL table, played against SQLite, Postgres and
|
|
74
|
+
* MySQL by the same contract — the same shape as the degraded job queue
|
|
75
|
+
* (`../queue/database.ts`), since a media library has no infrastructure
|
|
76
|
+
* dependency to fall back from in the first place (rule R1).
|
|
77
|
+
*/
|
|
78
|
+
export function createDatabaseMediaStore(options) {
|
|
79
|
+
const { db } = options;
|
|
80
|
+
const table = identifier(TABLE, db.dialect);
|
|
81
|
+
let ready = false;
|
|
82
|
+
async function ensureTable() {
|
|
83
|
+
if (ready)
|
|
84
|
+
return;
|
|
85
|
+
await db.query(sql `
|
|
86
|
+
create table if not exists ${table} (
|
|
87
|
+
id varchar(64) not null primary key,
|
|
88
|
+
kind varchar(16) not null,
|
|
89
|
+
filename varchar(512) not null,
|
|
90
|
+
mime_type varchar(255) not null,
|
|
91
|
+
size bigint not null,
|
|
92
|
+
width integer,
|
|
93
|
+
height integer,
|
|
94
|
+
alt text not null,
|
|
95
|
+
decorative boolean not null,
|
|
96
|
+
decorative_justification text,
|
|
97
|
+
focal text,
|
|
98
|
+
storage_key varchar(1024) not null,
|
|
99
|
+
created_at varchar(32) not null,
|
|
100
|
+
created_by varchar(255)
|
|
101
|
+
)`);
|
|
102
|
+
await db
|
|
103
|
+
.query(sql `create index ${identifier('cogenta_media_created', db.dialect)}
|
|
104
|
+
on ${table} (created_at, id)`)
|
|
105
|
+
.catch(() => undefined); // already there
|
|
106
|
+
ready = true;
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
create: async (input) => {
|
|
110
|
+
await ensureTable();
|
|
111
|
+
const decorative = input.decorative ?? false;
|
|
112
|
+
const alt = decorative ? '' : input.alt;
|
|
113
|
+
const justification = decorative ? (input.decorativeJustification ?? null) : null;
|
|
114
|
+
validateAltPolicy(alt, decorative, justification);
|
|
115
|
+
const id = input.id ?? randomUUID();
|
|
116
|
+
const createdAt = new Date().toISOString();
|
|
117
|
+
await db.query(sql `
|
|
118
|
+
insert into ${table}
|
|
119
|
+
(id, kind, filename, mime_type, size, width, height, alt, decorative,
|
|
120
|
+
decorative_justification, focal, storage_key, created_at, created_by)
|
|
121
|
+
values
|
|
122
|
+
(${id}, ${input.kind}, ${input.filename}, ${input.mimeType}, ${input.size},
|
|
123
|
+
${input.width ?? null}, ${input.height ?? null}, ${alt}, ${decorative},
|
|
124
|
+
${justification}, ${input.focal === undefined || input.focal === null ? null : JSON.stringify(input.focal)},
|
|
125
|
+
${input.storageKey}, ${createdAt}, ${input.createdBy ?? null})`);
|
|
126
|
+
return {
|
|
127
|
+
id,
|
|
128
|
+
kind: input.kind,
|
|
129
|
+
filename: input.filename,
|
|
130
|
+
mimeType: input.mimeType,
|
|
131
|
+
size: input.size,
|
|
132
|
+
width: input.width ?? null,
|
|
133
|
+
height: input.height ?? null,
|
|
134
|
+
alt,
|
|
135
|
+
decorative,
|
|
136
|
+
decorativeJustification: justification,
|
|
137
|
+
focal: input.focal ?? null,
|
|
138
|
+
storageKey: input.storageKey,
|
|
139
|
+
createdAt,
|
|
140
|
+
createdBy: input.createdBy ?? null,
|
|
141
|
+
};
|
|
142
|
+
},
|
|
143
|
+
get: async (id) => {
|
|
144
|
+
await ensureTable();
|
|
145
|
+
const result = await db.query(sql `select * from ${table} where id = ${id}`);
|
|
146
|
+
const row = result.rows[0];
|
|
147
|
+
return row === undefined ? null : rowToAsset(row);
|
|
148
|
+
},
|
|
149
|
+
list: async (listOptions = {}) => {
|
|
150
|
+
await ensureTable();
|
|
151
|
+
const pageSize = Math.min(listOptions.limit ?? DEFAULT_LIMIT, MAX_LIMIT);
|
|
152
|
+
const cursor = listOptions.cursor === undefined ? null : decodeCursor(listOptions.cursor);
|
|
153
|
+
const kindFilter = listOptions.kind === undefined ? sql `` : sql `and kind = ${listOptions.kind}`;
|
|
154
|
+
const cursorFilter = cursor === null
|
|
155
|
+
? sql ``
|
|
156
|
+
: sql `and (created_at < ${cursor.createdAt}
|
|
157
|
+
or (created_at = ${cursor.createdAt} and id < ${cursor.id}))`;
|
|
158
|
+
const result = await db.query(sql `
|
|
159
|
+
select * from ${table}
|
|
160
|
+
where 1 = 1 ${kindFilter} ${cursorFilter}
|
|
161
|
+
order by created_at desc, id desc
|
|
162
|
+
limit ${limit(pageSize + 1)}`);
|
|
163
|
+
const hasMore = result.rows.length > pageSize;
|
|
164
|
+
const page = result.rows.slice(0, pageSize).map(rowToAsset);
|
|
165
|
+
const last = page[page.length - 1];
|
|
166
|
+
return {
|
|
167
|
+
items: page,
|
|
168
|
+
hasMore,
|
|
169
|
+
nextCursor: hasMore && last !== undefined ? encodeCursor(last) : null,
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
update: async (id, input) => {
|
|
173
|
+
await ensureTable();
|
|
174
|
+
const existing = await db.query(sql `select * from ${table} where id = ${id}`);
|
|
175
|
+
const current = existing.rows[0];
|
|
176
|
+
if (current === undefined)
|
|
177
|
+
throw notFound(id);
|
|
178
|
+
const currentDecorative = current.decorative === true || current.decorative === 1;
|
|
179
|
+
const decorative = input.decorative ?? currentDecorative;
|
|
180
|
+
const alt = decorative ? '' : (input.alt ?? current.alt);
|
|
181
|
+
const justification = decorative
|
|
182
|
+
? (input.decorativeJustification ?? current.decorative_justification)
|
|
183
|
+
: null;
|
|
184
|
+
validateAltPolicy(alt, decorative, justification);
|
|
185
|
+
const focal = input.focal === undefined
|
|
186
|
+
? current.focal
|
|
187
|
+
: input.focal === null
|
|
188
|
+
? null
|
|
189
|
+
: JSON.stringify(input.focal);
|
|
190
|
+
await db.query(sql `
|
|
191
|
+
update ${table}
|
|
192
|
+
set alt = ${alt},
|
|
193
|
+
decorative = ${decorative},
|
|
194
|
+
decorative_justification = ${justification},
|
|
195
|
+
focal = ${focal}
|
|
196
|
+
where id = ${id}`);
|
|
197
|
+
return rowToAsset({
|
|
198
|
+
...current,
|
|
199
|
+
alt,
|
|
200
|
+
decorative,
|
|
201
|
+
decorative_justification: justification,
|
|
202
|
+
focal,
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
delete: async (id) => {
|
|
206
|
+
await ensureTable();
|
|
207
|
+
await db.query(sql `delete from ${table} where id = ${id}`);
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/media/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/** Where a media asset sits on the image on a page — never a crop, a hint the pipeline resizes and crops around. */
|
|
2
|
+
export interface FocalPoint {
|
|
3
|
+
readonly x: number;
|
|
4
|
+
readonly y: number;
|
|
5
|
+
}
|
|
6
|
+
export declare const MEDIA_KINDS: readonly ['image', 'video', 'audio', 'file'];
|
|
7
|
+
export type MediaKind = (typeof MEDIA_KINDS)[number];
|
|
8
|
+
export interface MediaAsset {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly kind: MediaKind;
|
|
11
|
+
readonly filename: string;
|
|
12
|
+
readonly mimeType: string;
|
|
13
|
+
/** Bytes of the stored original. */
|
|
14
|
+
readonly size: number;
|
|
15
|
+
/** Known for `image`; null for kinds this store never probes dimensions on. */
|
|
16
|
+
readonly width: number | null;
|
|
17
|
+
readonly height: number | null;
|
|
18
|
+
/**
|
|
19
|
+
* Empty for a declared-decorative asset (L2-admin.md's own rule: the
|
|
20
|
+
* decorative checkbox writes `alt=""`, never an invented description).
|
|
21
|
+
*/
|
|
22
|
+
readonly alt: string;
|
|
23
|
+
readonly decorative: boolean;
|
|
24
|
+
/** Why an editor marked it decorative — required exactly when `decorative` is true, kept for accessibility review, never rendered as `alt`. */
|
|
25
|
+
readonly decorativeJustification: string | null;
|
|
26
|
+
readonly focal: FocalPoint | null;
|
|
27
|
+
/** The `StorageDriver` key the original lives under. */
|
|
28
|
+
readonly storageKey: string;
|
|
29
|
+
readonly createdAt: string;
|
|
30
|
+
readonly createdBy: string | null;
|
|
31
|
+
}
|
|
32
|
+
export interface CreateMediaInput {
|
|
33
|
+
readonly id?: string;
|
|
34
|
+
readonly kind: MediaKind;
|
|
35
|
+
readonly filename: string;
|
|
36
|
+
readonly mimeType: string;
|
|
37
|
+
readonly size: number;
|
|
38
|
+
readonly width?: number | null;
|
|
39
|
+
readonly height?: number | null;
|
|
40
|
+
readonly alt: string;
|
|
41
|
+
readonly decorative?: boolean;
|
|
42
|
+
readonly decorativeJustification?: string | null;
|
|
43
|
+
readonly focal?: FocalPoint | null;
|
|
44
|
+
readonly storageKey: string;
|
|
45
|
+
readonly createdBy?: string | null;
|
|
46
|
+
}
|
|
47
|
+
export interface UpdateMediaInput {
|
|
48
|
+
readonly alt?: string;
|
|
49
|
+
readonly decorative?: boolean;
|
|
50
|
+
readonly decorativeJustification?: string | null;
|
|
51
|
+
readonly focal?: FocalPoint | null;
|
|
52
|
+
}
|
|
53
|
+
export interface ListMediaOptions {
|
|
54
|
+
readonly kind?: MediaKind;
|
|
55
|
+
readonly limit?: number;
|
|
56
|
+
readonly cursor?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface MediaPage {
|
|
59
|
+
readonly items: readonly MediaAsset[];
|
|
60
|
+
readonly nextCursor: string | null;
|
|
61
|
+
readonly hasMore: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface MediaStore {
|
|
64
|
+
create(input: CreateMediaInput): Promise<MediaAsset>;
|
|
65
|
+
get(id: string): Promise<MediaAsset | null>;
|
|
66
|
+
list(options?: ListMediaOptions): Promise<MediaPage>;
|
|
67
|
+
update(id: string, input: UpdateMediaInput): Promise<MediaAsset>;
|
|
68
|
+
delete(id: string): Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/media/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/media/types.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAU,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { Migrator, MigratorOptions } from './migrator.js';
|
|
2
|
+
export { createMigrator } from './migrator.js';
|
|
3
|
+
export type { Migration, MigrationOutcome, MigrationRecord, MigrationStatus, RollbackOptions, RunOptions, } from './types.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,eAAe,EACf,UAAU,GACX,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA"}
|