ugly-app 0.1.758 → 0.1.760
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/cli/version.d.ts +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/server/Storage.d.ts +3 -0
- package/dist/server/Storage.d.ts.map +1 -1
- package/dist/server/Storage.js +8 -0
- package/dist/server/Storage.js.map +1 -1
- package/dist/server/adapter/node/index.d.ts.map +1 -1
- package/dist/server/adapter/node/index.js +1 -0
- package/dist/server/adapter/node/index.js.map +1 -1
- package/dist/server/adapter/types.d.ts +7 -0
- package/dist/server/adapter/types.d.ts.map +1 -1
- package/dist/server/adapter/workers/storage.d.ts.map +1 -1
- package/dist/server/adapter/workers/storage.js +4 -0
- package/dist/server/adapter/workers/storage.js.map +1 -1
- package/dist/server/schemaIndexes.d.ts +12 -2
- package/dist/server/schemaIndexes.d.ts.map +1 -1
- package/dist/server/schemaIndexes.js +16 -11
- package/dist/server/schemaIndexes.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/version.ts +1 -1
- package/src/server/Storage.ts +18 -0
- package/src/server/adapter/node/index.ts +1 -0
- package/src/server/adapter/types.ts +8 -0
- package/src/server/adapter/workers/storage.ts +5 -0
- package/src/server/schemaIndexes.test.ts +31 -2
- package/src/server/schemaIndexes.ts +27 -12
package/dist/cli/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.1.
|
|
1
|
+
export declare const CLI_VERSION = "0.1.760";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/cli/version.js
CHANGED
package/dist/server/Storage.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ export interface StorageClient {
|
|
|
22
22
|
uploadUrl: string;
|
|
23
23
|
resultUrl: string;
|
|
24
24
|
}>;
|
|
25
|
+
/** Delete an object. Idempotent — S3/R2 treat deleting a missing key as
|
|
26
|
+
* success, so callers can sweep expired keys without pre-checking. */
|
|
27
|
+
delete(bucket: 'public' | 'temp', key: string): Promise<void>;
|
|
25
28
|
}
|
|
26
29
|
export interface StorageConfig {
|
|
27
30
|
accessKeyId?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../../src/server/Storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAYH,MAAM,WAAW,aAAa;IAC5B,GAAG,CACD,MAAM,EAAE,QAAQ,GAAG,MAAM,EACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChE,GAAG,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACpD,YAAY,CACV,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../../src/server/Storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAYH,MAAM,WAAW,aAAa;IAC5B,GAAG,CACD,MAAM,EAAE,QAAQ,GAAG,MAAM,EACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChE,GAAG,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACpD,YAAY,CACV,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD;2EACuE;IACvE,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAQD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAO5D;AA8DD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAErD;AAQD;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED,wBAAgB,WAAW,IAAI,IAAI,CAMlC;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAuFD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,CAuBnD"}
|
package/dist/server/Storage.js
CHANGED
|
@@ -127,6 +127,11 @@ async function moveToPublicRaw(tempKey, destKey) {
|
|
|
127
127
|
await client.send(new DeleteObjectCommand({ Bucket: cfg.tempBucket, Key: tempKey }));
|
|
128
128
|
return urlFor('public', destKey, cfg);
|
|
129
129
|
}
|
|
130
|
+
async function deleteRaw(bucket, key) {
|
|
131
|
+
const { client, cfg } = getClient();
|
|
132
|
+
const targetBucket = bucket === 'temp' ? cfg.tempBucket : cfg.bucket;
|
|
133
|
+
await client.send(new DeleteObjectCommand({ Bucket: targetBucket, Key: key }));
|
|
134
|
+
}
|
|
130
135
|
async function presignedPutRaw(bucket, key) {
|
|
131
136
|
const { client, cfg } = getClient();
|
|
132
137
|
const targetBucket = bucket === 'temp' ? cfg.tempBucket : cfg.bucket;
|
|
@@ -159,6 +164,9 @@ export function createStorageClient() {
|
|
|
159
164
|
async presignedPut(bucket, key) {
|
|
160
165
|
return presignedPutRaw(bucket, prefixKey(key));
|
|
161
166
|
},
|
|
167
|
+
async delete(bucket, key) {
|
|
168
|
+
return deleteRaw(bucket, prefixKey(key));
|
|
169
|
+
},
|
|
162
170
|
};
|
|
163
171
|
}
|
|
164
172
|
//# sourceMappingURL=Storage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Storage.js","sourceRoot":"","sources":["../../src/server/Storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,QAAQ,GACT,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"Storage.js","sourceRoot":"","sources":["../../src/server/Storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,QAAQ,GACT,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAqC7D,6EAA6E;AAE7E,IAAI,OAAO,GAAoB,IAAI,CAAC;AACpC,IAAI,OAAO,GAAkB,EAAE,CAAC;AAChC,IAAI,cAAc,GAAG,EAAE,CAAC;AAExB;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,8DAA8D,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC;AACtC,CAAC;AAaD,SAAS,aAAa;IACpB,MAAM,WAAW,GACf,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACzD,MAAM,eAAe,GACnB,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAChE,MAAM,aAAa,GACjB,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC;IAEnE,IAAI,CAAC,WAAW,IAAI,CAAC,eAAe,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CACb,yEAAyE;YACvE,6DAA6D,CAChE,CAAC;IACJ,CAAC;IAED,OAAO;QACL,WAAW;QACX,eAAe;QACf,MAAM;QACN,QAAQ;QACR,aAAa;QACb,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,MAAM;QACxC,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,aAAa;QACjD,oBAAoB,EAAE,OAAO,CAAC,oBAAoB,IAAI,IAAI;KAC3D,CAAC;AACJ,CAAC;AAED,IAAI,SAAS,GAA0B,IAAI,CAAC;AAE5C,SAAS,SAAS;IAChB,IAAI,OAAO,IAAI,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;IACrE,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,OAAO,GAAG,IAAI,QAAQ,CAAC;QACrB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,MAAM,EAAE,MAAM;QACd,WAAW,EAAE;YACX,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,eAAe,EAAE,GAAG,CAAC,eAAe;SACrC;QACD,cAAc,EAAE,IAAI;KACrB,CAAC,CAAC;IACH,SAAS,GAAG,GAAG,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAClC,CAAC;AAED,6EAA6E;AAE7E,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,cAAc,GAAG,MAAM,CAAC;AAC1B,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3D,CAAC;AAED,6EAA6E;AAE7E;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,SAAS,EAAE,CAAC;AACd,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,GAAG,IAAI,CAAC;QACf,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,OAAO,KAAK,IAAI,CAAC;AAC1B,CAAC;AAED,6EAA6E;AAE7E,SAAS,OAAO,CAAC,IAAY,EAAE,IAAY;IACzC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1C,OAAO,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,MAAM,CACb,MAAyB,EACzB,GAAW,EACX,GAAmB;IAEnB,MAAM,IAAI,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC;IACrE,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,6EAA6E;AAE7E,KAAK,UAAU,MAAM,CACnB,MAAyB,EACzB,GAAW,EACX,IAAY,EACZ,WAAmB;IAEnB,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;IACpC,MAAM,YAAY,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;IACrE,MAAM,MAAM,CAAC,IAAI,CACf,IAAI,gBAAgB,CAAC;QACnB,MAAM,EAAE,YAAY;QACpB,GAAG,EAAE,GAAG;QACR,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,WAAW;KACzB,CAAC,CACH,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAClC,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,OAAe,EACf,OAAe;IAEf,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;IACpC,MAAM,MAAM,CAAC,IAAI,CACf,IAAI,iBAAiB,CAAC;QACpB,UAAU,EAAE,GAAG,GAAG,CAAC,UAAU,IAAI,OAAO,EAAE;QAC1C,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,GAAG,EAAE,OAAO;KACb,CAAC,CACH,CAAC;IACF,MAAM,MAAM,CAAC,IAAI,CACf,IAAI,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAClE,CAAC;IACF,OAAO,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,SAAS,CACtB,MAAyB,EACzB,GAAW;IAEX,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;IACpC,MAAM,YAAY,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;IACrE,MAAM,MAAM,CAAC,IAAI,CACf,IAAI,mBAAmB,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAC5D,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,MAAc,EACd,GAAW;IAEX,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;IACpC,MAAM,YAAY,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;IACrE,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC;QACnC,MAAM,EAAE,YAAY;QACpB,GAAG,EAAE,GAAG;KACT,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE;QACpD,SAAS,EAAE,GAAG,CAAC,oBAAoB;KACpC,CAAC,CAAC;IACH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,6EAA6E;AAE7E;;;GAGG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW;YACtC,OAAO,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QAC3D,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO;YACjC,OAAO,eAAe,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QACjE,CAAC;QAED,GAAG,CAAC,MAAM,EAAE,GAAG;YACb,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;YAC5B,OAAO,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG;YAC5B,OAAO,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG;YACtB,OAAO,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3C,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/server/adapter/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAKV,aAAa,EAGd,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/server/adapter/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAKV,aAAa,EAGd,MAAM,aAAa,CAAC;AAuIrB,eAAO,MAAM,WAAW,EAAE,aAMzB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/server/adapter/node/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/server/adapter/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAWvD,yEAAyE;AACzE,sEAAsE;AACtE,oEAAoE;AACpE,mCAAmC;AAEnC,MAAM,MAAM,GAAc;IACxB,KAAK,CAAC,KAAK,CACT,GAAW,EACX,MAA+B;QAE/B,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,GAAG,EACH,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CACjC,CAAC;QACF,OAAO,MAAM,CAAC,IAAW,CAAC;IAC5B,CAAC;IACD,0DAA0D;IAC1D,+DAA+D;IAC/D,kCAAkC;CACnC,CAAC;AAEF,yEAAyE;AACzE,oEAAoE;AACpE,iEAAiE;AACjE,sEAAsE;AACtE,+DAA+D;AAE/D,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,GAAkB;IAChC,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,GAAkB;QAC7C,MAAM,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAChC,CAAC;IACD,SAAS,CACP,KAAa,EACb,QAAsC;QAEtC,IAAI,KAAK,GAAwB,IAAI,CAAC;QACtC,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,KAAK,aAAa,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;YACrC,IAAI,eAAe,CAAC,IAAI,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;YACb,IAAI,SAAS;gBAAE,EAAE,EAAE,CAAC;;gBACf,KAAK,GAAG,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;YACjB,IAAI,KAAK;gBAAE,KAAK,EAAE,CAAC;QACrB,CAAC,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,yEAAyE;AACzE,mEAAmE;AACnE,sEAAsE;AACtE,gEAAgE;AAEhE,IAAI,gBAAgB,GAA0B,IAAI,CAAC;AAEnD,SAAS,cAAc;IACrB,IAAI,gBAAgB;QAAE,OAAO,gBAAgB,CAAC;IAC9C,MAAM,MAAM,GAAG,mBAAmB,EAAE,CAAC;IACrC,gBAAgB,GAAG;QACjB,KAAK,CAAC,GAAG,CACP,MAAqB,EACrB,GAAW,EACX,IAAuC,EACvC,WAAmB;YAEnB,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAC/B,CAAC,CAAC,IAAI;gBACN,CAAC,CAAC,IAAI,YAAY,UAAU;oBAC1B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;oBACnB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YACxC,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;QACnD,CAAC;QACD,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC;QAC9C,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC;QAC9C,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;QAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;KACnC,CAAC;IACF,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,WAAW,GAAmB,IAAI,KAAK,CAAC,EAAoB,EAAE;IAClE,GAAG,CAAC,CAAC,EAAE,IAA0B;QAC/B,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;CACF,CAAC,CAAC;AAiBH,MAAM,YAAY,GAAG,IAAI,GAAG,EAAqB,CAAC;AAClD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAuB,CAAC;AAEtD,MAAM,YAAY,GAAoB;IACpC,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO;QAClC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI;QAChC,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,KAAK,CAAC,aAAa,CAAC,IAAY,EAAE,KAAc;QAC9C,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,GAAG,CAAC,CAAC;QACvE,iEAAiE;QACjE,oEAAoE;QACpE,gEAAgE;QAChE,MAAM,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAkB;IACxC,IAAI,EAAE,MAAM;IACZ,EAAE,EAAE,MAAM;IACV,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,WAAW;IACpB,QAAQ,EAAE,YAAY;CACvB,CAAC"}
|
|
@@ -114,6 +114,13 @@ export interface StorageAdapter {
|
|
|
114
114
|
}>;
|
|
115
115
|
moveToPublic(tempKey: string, destKey: string): Promise<string>;
|
|
116
116
|
url(bucket: StorageBucket, key: string): string;
|
|
117
|
+
/**
|
|
118
|
+
* Delete an object. Idempotent (deleting a missing key is a no-op success),
|
|
119
|
+
* so callers can sweep expired keys without pre-checking. Optional for
|
|
120
|
+
* back-compat — feature-detect via the presence of the method; both the
|
|
121
|
+
* Node (S3) and Workers (R2 binding) adapters implement it.
|
|
122
|
+
*/
|
|
123
|
+
delete?(bucket: StorageBucket, key: string): Promise<void>;
|
|
117
124
|
}
|
|
118
125
|
/**
|
|
119
126
|
* Cron + queue layer. Node adapter wires both to `setInterval` loops
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/server/adapter/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAKnD;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;OAKG;IACH,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,GAC9B,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAEhB;;;;;;OAMG;IACH,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChE;AAKD;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,QAAQ,IAClC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC3B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAO/B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9D;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B,uEAAuE;IACvE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1D;;;;OAIG;IACH,SAAS,CACP,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,GACrC,MAAM,IAAI,CAAC;CACf;AAKD;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9C;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,CACD,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,EACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB;;;;;;OAMG;IACH,YAAY,CAAC,CACX,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAErD,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEhE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/server/adapter/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../src/server/adapter/workers/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,aAAa,CAAC;AAOjE,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,QAAQ,EACZ,aAAa,EAAE,MAAM,GACpB,cAAc,
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../src/server/adapter/workers/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,aAAa,CAAC;AAOjE,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,QAAQ,EACZ,aAAa,EAAE,MAAM,GACpB,cAAc,CA0DhB"}
|
|
@@ -53,6 +53,10 @@ export function createWorkersStorage(r2, publicUrlBase) {
|
|
|
53
53
|
url(which, key) {
|
|
54
54
|
return `${publicUrlBase}/${prefixed(which, key)}`;
|
|
55
55
|
},
|
|
56
|
+
async delete(which, key) {
|
|
57
|
+
// R2 delete is idempotent — a missing key resolves without error.
|
|
58
|
+
await r2.delete(prefixed(which, key));
|
|
59
|
+
},
|
|
56
60
|
};
|
|
57
61
|
}
|
|
58
62
|
//# sourceMappingURL=storage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../../src/server/adapter/workers/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,MAAM,UAAU,GAAkC;IAChD,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,OAAO;CACd,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAClC,EAAY,EACZ,aAAqB;IAErB,MAAM,QAAQ,GAAG,CAAC,KAAoB,EAAE,GAAW,EAAU,EAAE,CAC7D,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC;IAE/B,OAAO;QACL,KAAK,CAAC,GAAG,CACP,KAAoB,EACpB,GAAW,EACX,IAAuC,EACvC,WAAmB;YAEnB,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACvC,iEAAiE;YACjE,2DAA2D;YAC3D,MAAM,EAAE,GACN,IAAI,YAAY,WAAW;gBACzB,CAAC,CAAC,IAAI;gBACN,CAAC,CAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAChB,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAClB,CAAC;YACxB,MAAM,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,EAAE;gBAC1B,YAAY,EAAE,EAAE,WAAW,EAAE;aAC9B,CAAC,CAAC;YACH,OAAO,GAAG,aAAa,IAAI,SAAS,EAAE,CAAC;QACzC,CAAC;QAED,iEAAiE;QACjE,+DAA+D;QAC/D,+DAA+D;QAC/D,kEAAkE;QAClE,+DAA+D;QAC/D,kEAAkE;QAClE,8DAA8D;QAE9D,KAAK,CAAC,YAAY,CAAC,OAAe,EAAE,OAAe;YACjD,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACxC,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CAAC,uCAAuC,OAAO,aAAa,CAAC,CAAC;YAC/E,CAAC;YACD,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE;gBAC1B,YAAY,EAAE,GAAG,CAAC,YAAY;aAC/B,CAAC,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACrB,OAAO,GAAG,aAAa,IAAI,GAAG,EAAE,CAAC;QACnC,CAAC;QAED,GAAG,CAAC,KAAoB,EAAE,GAAW;YACnC,OAAO,GAAG,aAAa,IAAI,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;QACpD,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../../src/server/adapter/workers/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,MAAM,UAAU,GAAkC;IAChD,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,OAAO;CACd,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAClC,EAAY,EACZ,aAAqB;IAErB,MAAM,QAAQ,GAAG,CAAC,KAAoB,EAAE,GAAW,EAAU,EAAE,CAC7D,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC;IAE/B,OAAO;QACL,KAAK,CAAC,GAAG,CACP,KAAoB,EACpB,GAAW,EACX,IAAuC,EACvC,WAAmB;YAEnB,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACvC,iEAAiE;YACjE,2DAA2D;YAC3D,MAAM,EAAE,GACN,IAAI,YAAY,WAAW;gBACzB,CAAC,CAAC,IAAI;gBACN,CAAC,CAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAChB,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAClB,CAAC;YACxB,MAAM,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,EAAE;gBAC1B,YAAY,EAAE,EAAE,WAAW,EAAE;aAC9B,CAAC,CAAC;YACH,OAAO,GAAG,aAAa,IAAI,SAAS,EAAE,CAAC;QACzC,CAAC;QAED,iEAAiE;QACjE,+DAA+D;QAC/D,+DAA+D;QAC/D,kEAAkE;QAClE,+DAA+D;QAC/D,kEAAkE;QAClE,8DAA8D;QAE9D,KAAK,CAAC,YAAY,CAAC,OAAe,EAAE,OAAe;YACjD,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACxC,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CAAC,uCAAuC,OAAO,aAAa,CAAC,CAAC;YAC/E,CAAC;YACD,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE;gBAC1B,YAAY,EAAE,GAAG,CAAC,YAAY;aAC/B,CAAC,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACrB,OAAO,GAAG,aAAa,IAAI,GAAG,EAAE,CAAC;QACnC,CAAC;QAED,GAAG,CAAC,KAAoB,EAAE,GAAW;YACnC,OAAO,GAAG,aAAa,IAAI,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;QACpD,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,KAAoB,EAAE,GAAW;YAC5C,kEAAkE;YAClE,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QACxC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Single source of truth for the btree expression indexes a collection declares
|
|
3
|
-
* via `indexes: [{ fields: { <field>: 1 } }]`.
|
|
3
|
+
* via `indexes: [{ fields: { <field>: 1 | -1, ... } }]`.
|
|
4
4
|
*
|
|
5
5
|
* The default `idx_<c>_data` GIN index covers JSONB containment (`data @> …`),
|
|
6
6
|
* but it CANNOT serve the scalar lookups the query layer actually emits
|
|
@@ -9,12 +9,22 @@
|
|
|
9
9
|
* sequential-scans — invisible on a small table, a hang once it grows past the
|
|
10
10
|
* 30s statement_timeout.
|
|
11
11
|
*
|
|
12
|
+
* Single-field AND composite (multi-field) indexes are emitted. A composite
|
|
13
|
+
* `{ fields: { a: 1, b: -1 } }` produces ONE btree over
|
|
14
|
+
* `((data->>'a'), (data->>'b') DESC)` — which serves a multi-field equality
|
|
15
|
+
* filter AND a matching `ORDER BY` in a single index seek. (A bitmap-AND of
|
|
16
|
+
* single-field indexes can satisfy the filter, but never the ordering.) Field
|
|
17
|
+
* order and per-field direction (1 = ASC, -1 = DESC) are preserved from the
|
|
18
|
+
* declaration; the `PostgresIndexes` coverage checker already credits every
|
|
19
|
+
* field of a composite expression index, so declaring one silences the
|
|
20
|
+
* per-field unindexed warning for all of its fields.
|
|
21
|
+
*
|
|
12
22
|
* Pure string-builder (no pg/pool imports) so it's safe to share across the Node
|
|
13
23
|
* schema sync (`PostgresSchema.ensureTable`), the Workers `/_init` route, and the
|
|
14
24
|
* migration generator (`schemaGen`). Statements are idempotent (IF NOT EXISTS) so
|
|
15
25
|
* every call site can run them on every deploy.
|
|
16
26
|
*/
|
|
17
27
|
import type { IndexDef } from '../shared/DB.js';
|
|
18
|
-
/** Raw `CREATE [UNIQUE] INDEX` SQL for each declared single-field index. */
|
|
28
|
+
/** Raw `CREATE [UNIQUE] INDEX` SQL for each declared (single- or multi-field) index. */
|
|
19
29
|
export declare function fieldIndexStatements(collection: string, indexes?: IndexDef[]): string[];
|
|
20
30
|
//# sourceMappingURL=schemaIndexes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemaIndexes.d.ts","sourceRoot":"","sources":["../../src/server/schemaIndexes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"schemaIndexes.d.ts","sourceRoot":"","sources":["../../src/server/schemaIndexes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,wFAAwF;AACxF,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,QAAQ,EAAE,GACnB,MAAM,EAAE,CAwBV"}
|
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
const VALID_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
2
|
-
/** Raw `CREATE [UNIQUE] INDEX` SQL for each declared single-field index. */
|
|
2
|
+
/** Raw `CREATE [UNIQUE] INDEX` SQL for each declared (single- or multi-field) index. */
|
|
3
3
|
export function fieldIndexStatements(collection, indexes) {
|
|
4
4
|
if (!VALID_NAME.test(collection))
|
|
5
5
|
return [];
|
|
6
6
|
const out = [];
|
|
7
7
|
for (const idx of indexes ?? []) {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
// filters one JSONB field at a time. (Composite indexes aren't emitted.)
|
|
11
|
-
if (fields.length !== 1)
|
|
8
|
+
const entries = Object.entries(idx.fields);
|
|
9
|
+
if (entries.length === 0)
|
|
12
10
|
continue;
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
// Reject the WHOLE index if any field name is unsafe — the names are
|
|
12
|
+
// interpolated straight into DDL, so there must be no injection surface.
|
|
13
|
+
if (!entries.every(([field]) => VALID_NAME.test(field)))
|
|
15
14
|
continue;
|
|
16
15
|
const unique = idx.unique ? 'UNIQUE ' : '';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
// `idx_<collection>_<f1>_<f2>_…` (+ `_unique`). Field order is significant —
|
|
17
|
+
// it matches the composite btree's leading-column order.
|
|
18
|
+
const base = `idx_${collection}_${entries.map(([field]) => field).join('_')}`;
|
|
19
|
+
const name = idx.unique ? `${base}_unique` : base;
|
|
20
|
+
// Each field is its own parenthesised expression; `-1` appends DESC so a
|
|
21
|
+
// filter+ORDER BY read is served entirely by the index.
|
|
22
|
+
const cols = entries
|
|
23
|
+
.map(([field, dir]) => `(data->>'${field}')${dir === -1 ? ' DESC' : ''}`)
|
|
24
|
+
.join(', ');
|
|
25
|
+
out.push(`CREATE ${unique}INDEX IF NOT EXISTS "${name}" ON "${collection}" (${cols})`);
|
|
21
26
|
}
|
|
22
27
|
return out;
|
|
23
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemaIndexes.js","sourceRoot":"","sources":["../../src/server/schemaIndexes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schemaIndexes.js","sourceRoot":"","sources":["../../src/server/schemaIndexes.ts"],"names":[],"mappings":"AA4BA,MAAM,UAAU,GAAG,0BAA0B,CAAC;AAE9C,wFAAwF;AACxF,MAAM,UAAU,oBAAoB,CAClC,UAAkB,EAClB,OAAoB;IAEpB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,CAAC;IAC5C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACnC,qEAAqE;QACrE,yEAAyE;QACzE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAAE,SAAS;QAClE,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,6EAA6E;QAC7E,yDAAyD;QACzD,MAAM,IAAI,GAAG,OAAO,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9E,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;QAClD,yEAAyE;QACzE,wDAAwD;QACxD,MAAM,IAAI,GAAG,OAAO;aACjB,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,YAAY,KAAK,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;aACxE,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,GAAG,CAAC,IAAI,CACN,UAAU,MAAM,wBAAwB,IAAI,SAAS,UAAU,MAAM,IAAI,GAAG,CAC7E,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ugly-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.760",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"comment:files": "Allowlist what ships to npm. dist = runtime; src = sourcemap targets (dist/*.js.map reference ../../src/); templates = CLI scaffold. Everything else at repo root (.pgdata local Postgres, coverage, assets/icons sources, test/, test-results/) is excluded by omission. The !negations strip the scaffold's installed deps + cruft (templates/node_modules is 200MB+ and must never ship). package.json/README/LICENSE ship automatically.",
|
|
6
6
|
"files": [
|
package/src/cli/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by prebuild — do not edit manually
|
|
2
|
-
export const CLI_VERSION = "0.1.
|
|
2
|
+
export const CLI_VERSION = "0.1.760";
|
package/src/server/Storage.ts
CHANGED
|
@@ -38,6 +38,9 @@ export interface StorageClient {
|
|
|
38
38
|
bucket: 'temp',
|
|
39
39
|
key: string,
|
|
40
40
|
): Promise<{ uploadUrl: string; resultUrl: string }>;
|
|
41
|
+
/** Delete an object. Idempotent — S3/R2 treat deleting a missing key as
|
|
42
|
+
* success, so callers can sweep expired keys without pre-checking. */
|
|
43
|
+
delete(bucket: 'public' | 'temp', key: string): Promise<void>;
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
export interface StorageConfig {
|
|
@@ -221,6 +224,17 @@ async function moveToPublicRaw(
|
|
|
221
224
|
return urlFor('public', destKey, cfg);
|
|
222
225
|
}
|
|
223
226
|
|
|
227
|
+
async function deleteRaw(
|
|
228
|
+
bucket: 'public' | 'temp',
|
|
229
|
+
key: string,
|
|
230
|
+
): Promise<void> {
|
|
231
|
+
const { client, cfg } = getClient();
|
|
232
|
+
const targetBucket = bucket === 'temp' ? cfg.tempBucket : cfg.bucket;
|
|
233
|
+
await client.send(
|
|
234
|
+
new DeleteObjectCommand({ Bucket: targetBucket, Key: key }),
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
224
238
|
async function presignedPutRaw(
|
|
225
239
|
bucket: 'temp',
|
|
226
240
|
key: string,
|
|
@@ -261,5 +275,9 @@ export function createStorageClient(): StorageClient {
|
|
|
261
275
|
async presignedPut(bucket, key) {
|
|
262
276
|
return presignedPutRaw(bucket, prefixKey(key));
|
|
263
277
|
},
|
|
278
|
+
|
|
279
|
+
async delete(bucket, key) {
|
|
280
|
+
return deleteRaw(bucket, prefixKey(key));
|
|
281
|
+
},
|
|
264
282
|
};
|
|
265
283
|
}
|
|
@@ -111,6 +111,7 @@ function getNodeStorage(): StorageAdapter {
|
|
|
111
111
|
presignedPut: client.presignedPut.bind(client),
|
|
112
112
|
moveToPublic: client.moveToPublic.bind(client),
|
|
113
113
|
url: client.url.bind(client),
|
|
114
|
+
delete: client.delete.bind(client),
|
|
114
115
|
};
|
|
115
116
|
return _storageInstance;
|
|
116
117
|
}
|
|
@@ -144,6 +144,14 @@ export interface StorageAdapter {
|
|
|
144
144
|
moveToPublic(tempKey: string, destKey: string): Promise<string>;
|
|
145
145
|
|
|
146
146
|
url(bucket: StorageBucket, key: string): string;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Delete an object. Idempotent (deleting a missing key is a no-op success),
|
|
150
|
+
* so callers can sweep expired keys without pre-checking. Optional for
|
|
151
|
+
* back-compat — feature-detect via the presence of the method; both the
|
|
152
|
+
* Node (S3) and Workers (R2 binding) adapters implement it.
|
|
153
|
+
*/
|
|
154
|
+
delete?(bucket: StorageBucket, key: string): Promise<void>;
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
// ──────────────────────────────────────────────────────────────────────
|
|
@@ -76,5 +76,10 @@ export function createWorkersStorage(
|
|
|
76
76
|
url(which: StorageBucket, key: string): string {
|
|
77
77
|
return `${publicUrlBase}/${prefixed(which, key)}`;
|
|
78
78
|
},
|
|
79
|
+
|
|
80
|
+
async delete(which: StorageBucket, key: string): Promise<void> {
|
|
81
|
+
// R2 delete is idempotent — a missing key resolves without error.
|
|
82
|
+
await r2.delete(prefixed(which, key));
|
|
83
|
+
},
|
|
79
84
|
};
|
|
80
85
|
}
|
|
@@ -28,17 +28,46 @@ describe('fieldIndexStatements', () => {
|
|
|
28
28
|
expect(sql[1]).toContain(`((data->>'provider'))`);
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
it('
|
|
32
|
-
|
|
31
|
+
it('emits ONE composite btree over all fields (order preserved)', () => {
|
|
32
|
+
const sql = fieldIndexStatements('codingSession', [
|
|
33
|
+
{ fields: { userId: 1, projectId: 1, kind: 1 } },
|
|
34
|
+
]);
|
|
35
|
+
expect(sql).toEqual([
|
|
36
|
+
`CREATE INDEX IF NOT EXISTS "idx_codingSession_userId_projectId_kind" ` +
|
|
37
|
+
`ON "codingSession" ((data->>'userId'), (data->>'projectId'), (data->>'kind'))`,
|
|
38
|
+
]);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('appends DESC for a -1 field so filter+ORDER BY is index-served', () => {
|
|
42
|
+
const sql = fieldIndexStatements('codingSession', [
|
|
43
|
+
{ fields: { userId: 1, updated: -1 } },
|
|
44
|
+
]);
|
|
45
|
+
expect(sql).toEqual([
|
|
46
|
+
`CREATE INDEX IF NOT EXISTS "idx_codingSession_userId_updated" ` +
|
|
47
|
+
`ON "codingSession" ((data->>'userId'), (data->>'updated') DESC)`,
|
|
48
|
+
]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('emits a UNIQUE composite index (with _unique suffix)', () => {
|
|
52
|
+
const sql = fieldIndexStatements('member', [
|
|
53
|
+
{ fields: { orgId: 1, userId: 1 }, unique: true },
|
|
54
|
+
]);
|
|
55
|
+
expect(sql).toEqual([
|
|
56
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS "idx_member_orgId_userId_unique" ` +
|
|
57
|
+
`ON "member" ((data->>'orgId'), (data->>'userId'))`,
|
|
58
|
+
]);
|
|
33
59
|
});
|
|
34
60
|
|
|
35
61
|
it('returns [] for no/empty indexes', () => {
|
|
36
62
|
expect(fieldIndexStatements('x')).toEqual([]);
|
|
37
63
|
expect(fieldIndexStatements('x', [])).toEqual([]);
|
|
64
|
+
expect(fieldIndexStatements('x', [{ fields: {} }])).toEqual([]);
|
|
38
65
|
});
|
|
39
66
|
|
|
40
67
|
it('refuses unsafe collection/field names (no SQL injection surface)', () => {
|
|
41
68
|
expect(fieldIndexStatements('bad-name', [{ fields: { userId: 1 } }])).toEqual([]);
|
|
42
69
|
expect(fieldIndexStatements('ok', [{ fields: { 'a; DROP TABLE x': 1 } }])).toEqual([]);
|
|
70
|
+
// one bad field poisons the whole composite index (no partial emit)
|
|
71
|
+
expect(fieldIndexStatements('ok', [{ fields: { userId: 1, 'a; DROP': 1 } }])).toEqual([]);
|
|
43
72
|
});
|
|
44
73
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Single source of truth for the btree expression indexes a collection declares
|
|
3
|
-
* via `indexes: [{ fields: { <field>: 1 } }]`.
|
|
3
|
+
* via `indexes: [{ fields: { <field>: 1 | -1, ... } }]`.
|
|
4
4
|
*
|
|
5
5
|
* The default `idx_<c>_data` GIN index covers JSONB containment (`data @> …`),
|
|
6
6
|
* but it CANNOT serve the scalar lookups the query layer actually emits
|
|
@@ -9,6 +9,16 @@
|
|
|
9
9
|
* sequential-scans — invisible on a small table, a hang once it grows past the
|
|
10
10
|
* 30s statement_timeout.
|
|
11
11
|
*
|
|
12
|
+
* Single-field AND composite (multi-field) indexes are emitted. A composite
|
|
13
|
+
* `{ fields: { a: 1, b: -1 } }` produces ONE btree over
|
|
14
|
+
* `((data->>'a'), (data->>'b') DESC)` — which serves a multi-field equality
|
|
15
|
+
* filter AND a matching `ORDER BY` in a single index seek. (A bitmap-AND of
|
|
16
|
+
* single-field indexes can satisfy the filter, but never the ordering.) Field
|
|
17
|
+
* order and per-field direction (1 = ASC, -1 = DESC) are preserved from the
|
|
18
|
+
* declaration; the `PostgresIndexes` coverage checker already credits every
|
|
19
|
+
* field of a composite expression index, so declaring one silences the
|
|
20
|
+
* per-field unindexed warning for all of its fields.
|
|
21
|
+
*
|
|
12
22
|
* Pure string-builder (no pg/pool imports) so it's safe to share across the Node
|
|
13
23
|
* schema sync (`PostgresSchema.ensureTable`), the Workers `/_init` route, and the
|
|
14
24
|
* migration generator (`schemaGen`). Statements are idempotent (IF NOT EXISTS) so
|
|
@@ -18,7 +28,7 @@ import type { IndexDef } from '../shared/DB.js';
|
|
|
18
28
|
|
|
19
29
|
const VALID_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
20
30
|
|
|
21
|
-
/** Raw `CREATE [UNIQUE] INDEX` SQL for each declared single-field index. */
|
|
31
|
+
/** Raw `CREATE [UNIQUE] INDEX` SQL for each declared (single- or multi-field) index. */
|
|
22
32
|
export function fieldIndexStatements(
|
|
23
33
|
collection: string,
|
|
24
34
|
indexes?: IndexDef[],
|
|
@@ -26,18 +36,23 @@ export function fieldIndexStatements(
|
|
|
26
36
|
if (!VALID_NAME.test(collection)) return [];
|
|
27
37
|
const out: string[] = [];
|
|
28
38
|
for (const idx of indexes ?? []) {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (!VALID_NAME.test(field)) continue;
|
|
39
|
+
const entries = Object.entries(idx.fields);
|
|
40
|
+
if (entries.length === 0) continue;
|
|
41
|
+
// Reject the WHOLE index if any field name is unsafe — the names are
|
|
42
|
+
// interpolated straight into DDL, so there must be no injection surface.
|
|
43
|
+
if (!entries.every(([field]) => VALID_NAME.test(field))) continue;
|
|
35
44
|
const unique = idx.unique ? 'UNIQUE ' : '';
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
// `idx_<collection>_<f1>_<f2>_…` (+ `_unique`). Field order is significant —
|
|
46
|
+
// it matches the composite btree's leading-column order.
|
|
47
|
+
const base = `idx_${collection}_${entries.map(([field]) => field).join('_')}`;
|
|
48
|
+
const name = idx.unique ? `${base}_unique` : base;
|
|
49
|
+
// Each field is its own parenthesised expression; `-1` appends DESC so a
|
|
50
|
+
// filter+ORDER BY read is served entirely by the index.
|
|
51
|
+
const cols = entries
|
|
52
|
+
.map(([field, dir]) => `(data->>'${field}')${dir === -1 ? ' DESC' : ''}`)
|
|
53
|
+
.join(', ');
|
|
39
54
|
out.push(
|
|
40
|
-
`CREATE ${unique}INDEX IF NOT EXISTS "${name}" ON "${collection}" (
|
|
55
|
+
`CREATE ${unique}INDEX IF NOT EXISTS "${name}" ON "${collection}" (${cols})`,
|
|
41
56
|
);
|
|
42
57
|
}
|
|
43
58
|
return out;
|