@caretcms/cloudflare 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/LICENSE +21 -0
- package/README.md +32 -0
- package/dist/adapters/kv-storage.d.ts +51 -0
- package/dist/adapters/kv-storage.d.ts.map +1 -0
- package/dist/adapters/kv-storage.js +290 -0
- package/dist/adapters/kv-storage.js.map +1 -0
- package/dist/adapters/r2-upload.d.ts +30 -0
- package/dist/adapters/r2-upload.d.ts.map +1 -0
- package/dist/adapters/r2-upload.js +112 -0
- package/dist/adapters/r2-upload.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/storage.d.ts +5 -0
- package/dist/providers/storage.d.ts.map +1 -0
- package/dist/providers/storage.js +13 -0
- package/dist/providers/storage.js.map +1 -0
- package/dist/providers/uploads.d.ts +5 -0
- package/dist/providers/uploads.d.ts.map +1 -0
- package/dist/providers/uploads.js +13 -0
- package/dist/providers/uploads.js.map +1 -0
- package/dist/runtime/env.d.ts +3 -0
- package/dist/runtime/env.d.ts.map +1 -0
- package/dist/runtime/env.js +11 -0
- package/dist/runtime/env.js.map +1 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 techstacked
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# @caretcms/cloudflare
|
|
2
|
+
|
|
3
|
+
Cloudflare-native storage, uploads, and runtime helpers for CaretCMS.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import { defineConfig } from "astro/config";
|
|
9
|
+
import caret from "@caretcms/core";
|
|
10
|
+
import { cloudflareStorage, r2Uploads } from "@caretcms/cloudflare";
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
output: "server",
|
|
14
|
+
integrations: [
|
|
15
|
+
caret({
|
|
16
|
+
mode: "embedded",
|
|
17
|
+
storage: cloudflareStorage({ binding: "CMS_KV" }),
|
|
18
|
+
uploads: r2Uploads({ binding: "CMS_R2" }),
|
|
19
|
+
}),
|
|
20
|
+
],
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Exports
|
|
25
|
+
|
|
26
|
+
- `cloudflareStorage()`
|
|
27
|
+
- `cloudflareStorageProvider()`
|
|
28
|
+
- `CloudflareKvStorageAdapter`
|
|
29
|
+
- `r2Uploads()`
|
|
30
|
+
- `r2UploadsProvider()`
|
|
31
|
+
- `R2UploadHandler`
|
|
32
|
+
- `getCloudflareRuntimeEnv()`
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { CollectionMetadata, EntryData, HistoryEntry, StorageAdapter } from "@caretcms/core";
|
|
2
|
+
export interface CloudflareKvStorageOptions extends Record<string, unknown> {
|
|
3
|
+
binding?: string;
|
|
4
|
+
/** Prepended to every KV key. Used by session overlays. */
|
|
5
|
+
keyPrefix?: string;
|
|
6
|
+
/** Applied to every put. Used by session overlays for native expiry. */
|
|
7
|
+
expirationTtl?: number;
|
|
8
|
+
/** Disables the bundled .caret/data fallback (overlays don't want it). */
|
|
9
|
+
bundledFallback?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare class CloudflareKvStorageAdapter implements StorageAdapter {
|
|
12
|
+
private readonly binding;
|
|
13
|
+
private readonly keyPrefix;
|
|
14
|
+
private readonly expirationTtl;
|
|
15
|
+
private readonly bundledFallback;
|
|
16
|
+
constructor(options?: CloudflareKvStorageOptions);
|
|
17
|
+
private k;
|
|
18
|
+
private revisionKey;
|
|
19
|
+
private indexKey;
|
|
20
|
+
private historyKey;
|
|
21
|
+
private entryKey;
|
|
22
|
+
private metaKey;
|
|
23
|
+
private collectionsKey;
|
|
24
|
+
private put;
|
|
25
|
+
private requireKv;
|
|
26
|
+
private getRevisionRaw;
|
|
27
|
+
private setRevisionRaw;
|
|
28
|
+
private getCollectionIndex;
|
|
29
|
+
private getKnownCollections;
|
|
30
|
+
private addKnownCollection;
|
|
31
|
+
private removeKnownCollection;
|
|
32
|
+
private addToIndex;
|
|
33
|
+
private removeFromIndex;
|
|
34
|
+
discoverCollections(): Promise<string[]>;
|
|
35
|
+
isKnownCollection(collection: string): Promise<boolean>;
|
|
36
|
+
getEntry(collection: string, id: string): Promise<EntryData | null>;
|
|
37
|
+
listEntryIds(collection: string): Promise<string[]>;
|
|
38
|
+
listEntries(collection: string): Promise<EntryData[]>;
|
|
39
|
+
writeEntry(collection: string, id: string, data: Record<string, unknown>): Promise<void>;
|
|
40
|
+
deleteEntry(collection: string, id: string): Promise<void>;
|
|
41
|
+
getRevision(collection: string, id: string): Promise<number>;
|
|
42
|
+
bumpRevision(collection: string, id: string): Promise<number>;
|
|
43
|
+
getHistory(collection: string, id: string): Promise<HistoryEntry[]>;
|
|
44
|
+
appendHistory(collection: string, id: string, entry: HistoryEntry): Promise<void>;
|
|
45
|
+
createCollection(metadata: CollectionMetadata): Promise<void>;
|
|
46
|
+
deleteCollection(collection: string): Promise<void>;
|
|
47
|
+
getCollectionMetadata(collection: string): Promise<CollectionMetadata | null>;
|
|
48
|
+
listCollectionMetadata(): Promise<CollectionMetadata[]>;
|
|
49
|
+
makeSessionOverlay(sessionId: string): Promise<StorageAdapter>;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=kv-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kv-storage.d.ts","sourceRoot":"","sources":["../../src/adapters/kv-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,SAAS,EACT,YAAY,EACZ,cAAc,EACf,MAAM,gBAAgB,CAAC;AA4FxB,MAAM,WAAW,0BAA2B,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,qBAAa,0BAA2B,YAAW,cAAc;IAC/D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;gBAE9B,OAAO,GAAE,0BAA+B;IASpD,OAAO,CAAC,CAAC;IAGT,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,cAAc;YAER,GAAG;YAQH,SAAS;YAYT,cAAc;YAKd,cAAc;YAId,kBAAkB;YAalB,mBAAmB;YAenB,kBAAkB;YAQlB,qBAAqB;YAUrB,UAAU;YAQV,eAAe;IAWvB,mBAAmB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAQxC,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMvD,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAYnE,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAKnD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAMrD,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxF,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM1D,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK5D,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO7D,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAoBnE,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjF,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAe7D,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnD,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAO7E,sBAAsB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;IASvD,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAQrE"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { getCloudflareRuntimeEnv } from "../runtime/env.js";
|
|
2
|
+
const COLLECTION_NAME_RE = /^[a-z][a-z0-9_-]*$/;
|
|
3
|
+
const HISTORY_LIMIT = 50;
|
|
4
|
+
const COLLECTIONS_KEY = "collections";
|
|
5
|
+
const META_PREFIX = "meta::";
|
|
6
|
+
const SESSION_OVERLAY_TTL_SECONDS = 60 * 60 * 2; // 2h, matches demo cookie
|
|
7
|
+
let _bundled = null;
|
|
8
|
+
function getDataModules() {
|
|
9
|
+
if (_bundled)
|
|
10
|
+
return _bundled;
|
|
11
|
+
try {
|
|
12
|
+
_bundled = import.meta.glob("/.caret/data/**/*.json", { eager: true, import: "default" });
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
_bundled = {};
|
|
16
|
+
}
|
|
17
|
+
return _bundled;
|
|
18
|
+
}
|
|
19
|
+
function isObjectRecord(value) {
|
|
20
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21
|
+
}
|
|
22
|
+
function isCollectionMetadata(value) {
|
|
23
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
24
|
+
return false;
|
|
25
|
+
const obj = value;
|
|
26
|
+
return (typeof obj.id === "string" &&
|
|
27
|
+
typeof obj.label === "string" &&
|
|
28
|
+
typeof obj.created_at === "number" &&
|
|
29
|
+
typeof obj.updated_at === "number" &&
|
|
30
|
+
!!obj.schema &&
|
|
31
|
+
typeof obj.schema === "object");
|
|
32
|
+
}
|
|
33
|
+
function readBundledEntry(collection, id) {
|
|
34
|
+
const key = `/.caret/data/${collection}/${id}.json`;
|
|
35
|
+
const data = getDataModules()[key];
|
|
36
|
+
return data && isObjectRecord(data) ? structuredClone(data) : null;
|
|
37
|
+
}
|
|
38
|
+
function listBundledEntryIds(collection) {
|
|
39
|
+
const prefix = `/.caret/data/${collection}/`;
|
|
40
|
+
return Object.keys(getDataModules())
|
|
41
|
+
.filter((key) => key.startsWith(prefix))
|
|
42
|
+
.map((key) => key.slice(prefix.length, -".json".length))
|
|
43
|
+
.sort((a, b) => a.localeCompare(b));
|
|
44
|
+
}
|
|
45
|
+
function discoverBundledCollections() {
|
|
46
|
+
const collections = new Set();
|
|
47
|
+
for (const key of Object.keys(getDataModules())) {
|
|
48
|
+
const match = /^\/\.caret\/data\/([^/]+)\/[^/]+\.json$/.exec(key);
|
|
49
|
+
if (match && COLLECTION_NAME_RE.test(match[1])) {
|
|
50
|
+
collections.add(match[1]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return [...collections].sort((a, b) => a.localeCompare(b));
|
|
54
|
+
}
|
|
55
|
+
async function getKvBinding(binding) {
|
|
56
|
+
const env = await getCloudflareRuntimeEnv();
|
|
57
|
+
const candidate = env?.[binding];
|
|
58
|
+
if (!candidate || typeof candidate !== "object")
|
|
59
|
+
return null;
|
|
60
|
+
const kv = candidate;
|
|
61
|
+
if (typeof kv.get !== "function" ||
|
|
62
|
+
typeof kv.put !== "function" ||
|
|
63
|
+
typeof kv.delete !== "function") {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return candidate;
|
|
67
|
+
}
|
|
68
|
+
export class CloudflareKvStorageAdapter {
|
|
69
|
+
binding;
|
|
70
|
+
keyPrefix;
|
|
71
|
+
expirationTtl;
|
|
72
|
+
bundledFallback;
|
|
73
|
+
constructor(options = {}) {
|
|
74
|
+
this.binding = options.binding ?? "CMS_KV";
|
|
75
|
+
this.keyPrefix = options.keyPrefix ?? "";
|
|
76
|
+
this.expirationTtl = options.expirationTtl;
|
|
77
|
+
this.bundledFallback = options.bundledFallback ?? true;
|
|
78
|
+
}
|
|
79
|
+
// --- key helpers -------------------------------------------------------
|
|
80
|
+
k(suffix) {
|
|
81
|
+
return `${this.keyPrefix}${suffix}`;
|
|
82
|
+
}
|
|
83
|
+
revisionKey(c, id) { return this.k(`rev::${c}::${id}`); }
|
|
84
|
+
indexKey(c) { return this.k(`index::${c}`); }
|
|
85
|
+
historyKey(c, id) { return this.k(`history::${c}::${id}`); }
|
|
86
|
+
entryKey(c, id) { return this.k(`${c}::${id}`); }
|
|
87
|
+
metaKey(c) { return this.k(`${META_PREFIX}${c}`); }
|
|
88
|
+
collectionsKey() { return this.k(COLLECTIONS_KEY); }
|
|
89
|
+
async put(kv, key, value) {
|
|
90
|
+
if (this.expirationTtl) {
|
|
91
|
+
await kv.put(key, value, { expirationTtl: this.expirationTtl });
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
await kv.put(key, value);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async requireKv() {
|
|
98
|
+
const kv = await getKvBinding(this.binding);
|
|
99
|
+
if (!kv) {
|
|
100
|
+
throw new Error(`[caretcms] Cloudflare KV binding "${this.binding}" is not available.`);
|
|
101
|
+
}
|
|
102
|
+
return kv;
|
|
103
|
+
}
|
|
104
|
+
// --- collection / index plumbing --------------------------------------
|
|
105
|
+
async getRevisionRaw(kv, c, id) {
|
|
106
|
+
const raw = await kv.get(this.revisionKey(c, id), "json");
|
|
107
|
+
return typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? raw : 0;
|
|
108
|
+
}
|
|
109
|
+
async setRevisionRaw(kv, c, id, rev) {
|
|
110
|
+
await this.put(kv, this.revisionKey(c, id), JSON.stringify(rev));
|
|
111
|
+
}
|
|
112
|
+
async getCollectionIndex(kv, c) {
|
|
113
|
+
const existing = await kv.get(this.indexKey(c), "json");
|
|
114
|
+
if (Array.isArray(existing)) {
|
|
115
|
+
return existing.filter((value) => typeof value === "string");
|
|
116
|
+
}
|
|
117
|
+
if (!this.bundledFallback)
|
|
118
|
+
return [];
|
|
119
|
+
const bundled = listBundledEntryIds(c);
|
|
120
|
+
await this.put(kv, this.indexKey(c), JSON.stringify(bundled));
|
|
121
|
+
return bundled;
|
|
122
|
+
}
|
|
123
|
+
async getKnownCollections(kv) {
|
|
124
|
+
const existing = await kv.get(this.collectionsKey(), "json");
|
|
125
|
+
if (Array.isArray(existing)) {
|
|
126
|
+
return existing
|
|
127
|
+
.filter((v) => typeof v === "string" && COLLECTION_NAME_RE.test(v))
|
|
128
|
+
.sort((a, b) => a.localeCompare(b));
|
|
129
|
+
}
|
|
130
|
+
if (!this.bundledFallback)
|
|
131
|
+
return [];
|
|
132
|
+
const bundled = discoverBundledCollections();
|
|
133
|
+
await this.put(kv, this.collectionsKey(), JSON.stringify(bundled));
|
|
134
|
+
return bundled;
|
|
135
|
+
}
|
|
136
|
+
async addKnownCollection(kv, c) {
|
|
137
|
+
const collections = await this.getKnownCollections(kv);
|
|
138
|
+
if (collections.includes(c))
|
|
139
|
+
return;
|
|
140
|
+
collections.push(c);
|
|
141
|
+
collections.sort((a, b) => a.localeCompare(b));
|
|
142
|
+
await this.put(kv, this.collectionsKey(), JSON.stringify(collections));
|
|
143
|
+
}
|
|
144
|
+
async removeKnownCollection(kv, c) {
|
|
145
|
+
const collections = await this.getKnownCollections(kv);
|
|
146
|
+
if (!collections.includes(c))
|
|
147
|
+
return;
|
|
148
|
+
await this.put(kv, this.collectionsKey(), JSON.stringify(collections.filter((value) => value !== c)));
|
|
149
|
+
}
|
|
150
|
+
async addToIndex(kv, c, id) {
|
|
151
|
+
const ids = await this.getCollectionIndex(kv, c);
|
|
152
|
+
if (ids.includes(id))
|
|
153
|
+
return;
|
|
154
|
+
ids.push(id);
|
|
155
|
+
ids.sort((a, b) => a.localeCompare(b));
|
|
156
|
+
await this.put(kv, this.indexKey(c), JSON.stringify(ids));
|
|
157
|
+
}
|
|
158
|
+
async removeFromIndex(kv, c, id) {
|
|
159
|
+
const ids = await this.getCollectionIndex(kv, c);
|
|
160
|
+
await this.put(kv, this.indexKey(c), JSON.stringify(ids.filter((value) => value !== id)));
|
|
161
|
+
}
|
|
162
|
+
// --- StorageAdapter ----------------------------------------------------
|
|
163
|
+
async discoverCollections() {
|
|
164
|
+
const kv = await this.requireKv();
|
|
165
|
+
const known = await this.getKnownCollections(kv);
|
|
166
|
+
if (!this.bundledFallback)
|
|
167
|
+
return known;
|
|
168
|
+
const bundled = discoverBundledCollections();
|
|
169
|
+
return [...new Set([...known, ...bundled])].sort((a, b) => a.localeCompare(b));
|
|
170
|
+
}
|
|
171
|
+
async isKnownCollection(collection) {
|
|
172
|
+
if (!COLLECTION_NAME_RE.test(collection))
|
|
173
|
+
return false;
|
|
174
|
+
const collections = await this.discoverCollections();
|
|
175
|
+
return collections.includes(collection);
|
|
176
|
+
}
|
|
177
|
+
async getEntry(collection, id) {
|
|
178
|
+
const kv = await this.requireKv();
|
|
179
|
+
const raw = await kv.get(this.entryKey(collection, id), "json");
|
|
180
|
+
if (isObjectRecord(raw)) {
|
|
181
|
+
return { id, data: structuredClone(raw) };
|
|
182
|
+
}
|
|
183
|
+
if (!this.bundledFallback)
|
|
184
|
+
return null;
|
|
185
|
+
const bundled = readBundledEntry(collection, id);
|
|
186
|
+
return bundled ? { id, data: bundled } : null;
|
|
187
|
+
}
|
|
188
|
+
async listEntryIds(collection) {
|
|
189
|
+
const kv = await this.requireKv();
|
|
190
|
+
return this.getCollectionIndex(kv, collection);
|
|
191
|
+
}
|
|
192
|
+
async listEntries(collection) {
|
|
193
|
+
const ids = await this.listEntryIds(collection);
|
|
194
|
+
const entries = await Promise.all(ids.map((id) => this.getEntry(collection, id)));
|
|
195
|
+
return entries.filter((entry) => Boolean(entry));
|
|
196
|
+
}
|
|
197
|
+
async writeEntry(collection, id, data) {
|
|
198
|
+
const kv = await this.requireKv();
|
|
199
|
+
await this.addKnownCollection(kv, collection);
|
|
200
|
+
await this.put(kv, this.entryKey(collection, id), JSON.stringify(data));
|
|
201
|
+
await this.addToIndex(kv, collection, id);
|
|
202
|
+
}
|
|
203
|
+
async deleteEntry(collection, id) {
|
|
204
|
+
const kv = await this.requireKv();
|
|
205
|
+
await kv.delete(this.entryKey(collection, id));
|
|
206
|
+
await this.removeFromIndex(kv, collection, id);
|
|
207
|
+
}
|
|
208
|
+
async getRevision(collection, id) {
|
|
209
|
+
const kv = await this.requireKv();
|
|
210
|
+
return this.getRevisionRaw(kv, collection, id);
|
|
211
|
+
}
|
|
212
|
+
async bumpRevision(collection, id) {
|
|
213
|
+
const kv = await this.requireKv();
|
|
214
|
+
const next = (await this.getRevisionRaw(kv, collection, id)) + 1;
|
|
215
|
+
await this.setRevisionRaw(kv, collection, id, next);
|
|
216
|
+
return next;
|
|
217
|
+
}
|
|
218
|
+
async getHistory(collection, id) {
|
|
219
|
+
const kv = await this.requireKv();
|
|
220
|
+
const raw = await kv.get(this.historyKey(collection, id), "json");
|
|
221
|
+
if (!Array.isArray(raw))
|
|
222
|
+
return [];
|
|
223
|
+
return raw
|
|
224
|
+
.filter((entry) => {
|
|
225
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
226
|
+
return false;
|
|
227
|
+
const c = entry;
|
|
228
|
+
return (typeof c.ts === "number" &&
|
|
229
|
+
Number.isFinite(c.ts) &&
|
|
230
|
+
typeof c.action === "string" &&
|
|
231
|
+
"data" in c);
|
|
232
|
+
})
|
|
233
|
+
.slice(0, HISTORY_LIMIT)
|
|
234
|
+
.map((entry) => structuredClone(entry));
|
|
235
|
+
}
|
|
236
|
+
async appendHistory(collection, id, entry) {
|
|
237
|
+
const kv = await this.requireKv();
|
|
238
|
+
const current = await this.getHistory(collection, id);
|
|
239
|
+
const next = [structuredClone(entry), ...current].slice(0, HISTORY_LIMIT);
|
|
240
|
+
await this.put(kv, this.historyKey(collection, id), JSON.stringify(next));
|
|
241
|
+
}
|
|
242
|
+
async createCollection(metadata) {
|
|
243
|
+
if (!COLLECTION_NAME_RE.test(metadata.id)) {
|
|
244
|
+
throw new Error(`[caretcms] Invalid collection id "${metadata.id}". Must match ${COLLECTION_NAME_RE}.`);
|
|
245
|
+
}
|
|
246
|
+
const kv = await this.requireKv();
|
|
247
|
+
await this.put(kv, this.metaKey(metadata.id), JSON.stringify(metadata));
|
|
248
|
+
await this.addKnownCollection(kv, metadata.id);
|
|
249
|
+
const existingIndex = await kv.get(this.indexKey(metadata.id), "json");
|
|
250
|
+
if (!Array.isArray(existingIndex)) {
|
|
251
|
+
await this.put(kv, this.indexKey(metadata.id), JSON.stringify([]));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
async deleteCollection(collection) {
|
|
255
|
+
if (!COLLECTION_NAME_RE.test(collection))
|
|
256
|
+
return;
|
|
257
|
+
const kv = await this.requireKv();
|
|
258
|
+
const ids = await this.getCollectionIndex(kv, collection);
|
|
259
|
+
await Promise.all(ids.map((id) => Promise.all([
|
|
260
|
+
kv.delete(this.entryKey(collection, id)),
|
|
261
|
+
kv.delete(this.revisionKey(collection, id)),
|
|
262
|
+
kv.delete(this.historyKey(collection, id)),
|
|
263
|
+
])));
|
|
264
|
+
await kv.delete(this.indexKey(collection));
|
|
265
|
+
await kv.delete(this.metaKey(collection));
|
|
266
|
+
await this.removeKnownCollection(kv, collection);
|
|
267
|
+
}
|
|
268
|
+
async getCollectionMetadata(collection) {
|
|
269
|
+
if (!COLLECTION_NAME_RE.test(collection))
|
|
270
|
+
return null;
|
|
271
|
+
const kv = await this.requireKv();
|
|
272
|
+
const raw = await kv.get(this.metaKey(collection), "json");
|
|
273
|
+
return isCollectionMetadata(raw) ? structuredClone(raw) : null;
|
|
274
|
+
}
|
|
275
|
+
async listCollectionMetadata() {
|
|
276
|
+
const kv = await this.requireKv();
|
|
277
|
+
const collections = await this.getKnownCollections(kv);
|
|
278
|
+
const entries = await Promise.all(collections.map((c) => this.getCollectionMetadata(c)));
|
|
279
|
+
return entries.filter((value) => Boolean(value));
|
|
280
|
+
}
|
|
281
|
+
async makeSessionOverlay(sessionId) {
|
|
282
|
+
return new CloudflareKvStorageAdapter({
|
|
283
|
+
binding: this.binding,
|
|
284
|
+
keyPrefix: `session/${sessionId}/`,
|
|
285
|
+
expirationTtl: SESSION_OVERLAY_TTL_SECONDS,
|
|
286
|
+
bundledFallback: false,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=kv-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kv-storage.js","sourceRoot":"","sources":["../../src/adapters/kv-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { UploadContext, UploadHandler } from "@caretcms/core";
|
|
2
|
+
export interface R2UploadHandlerOptions extends Record<string, unknown> {
|
|
3
|
+
binding?: string;
|
|
4
|
+
publicBaseUrl?: string;
|
|
5
|
+
devServePath?: string;
|
|
6
|
+
/**
|
|
7
|
+
* KV binding used to track per-session upload byte totals when demo mode is
|
|
8
|
+
* active. Defaults to "CMS_KV" — the same binding used by the storage
|
|
9
|
+
* adapter's session overlay.
|
|
10
|
+
*/
|
|
11
|
+
quotaBinding?: string;
|
|
12
|
+
/** Per-file size cap in demo sandboxes. Defaults to 5MB. */
|
|
13
|
+
sandboxPerFileBytes?: number;
|
|
14
|
+
/** Per-session total upload cap in demo sandboxes. Defaults to 25MB. */
|
|
15
|
+
sandboxPerSessionBytes?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class R2UploadHandler implements UploadHandler {
|
|
18
|
+
private readonly binding;
|
|
19
|
+
private readonly publicBaseUrl;
|
|
20
|
+
private readonly devServePath;
|
|
21
|
+
private readonly quotaBinding;
|
|
22
|
+
private readonly sandboxPerFileBytes;
|
|
23
|
+
private readonly sandboxPerSessionBytes;
|
|
24
|
+
constructor(options?: R2UploadHandlerOptions);
|
|
25
|
+
makeSessionWrapper(_sessionId: string): Promise<UploadHandler>;
|
|
26
|
+
upload(file: File, ctx?: UploadContext): Promise<{
|
|
27
|
+
url: string;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=r2-upload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"r2-upload.d.ts","sourceRoot":"","sources":["../../src/adapters/r2-upload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AA6FnE,MAAM,WAAW,sBAAuB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,qBAAa,eAAgB,YAAW,aAAa;IACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;gBAEpC,OAAO,GAAE,sBAA2B;IAS1C,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAS9D,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAgCxE"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { IMAGE_KIND_TO_EXT, QuotaUploadHandler, readAndValidateImage, sanitizeImageBaseName, } from "@caretcms/core/runtime";
|
|
2
|
+
import { getCloudflareRuntimeEnv } from "../runtime/env.js";
|
|
3
|
+
const KIND_TO_CONTENT_TYPE = {
|
|
4
|
+
jpeg: "image/jpeg",
|
|
5
|
+
png: "image/png",
|
|
6
|
+
webp: "image/webp",
|
|
7
|
+
avif: "image/avif",
|
|
8
|
+
};
|
|
9
|
+
const QUOTA_TTL_SECONDS = 60 * 60 * 2; // matches demo session window
|
|
10
|
+
class KvQuotaCounter {
|
|
11
|
+
binding;
|
|
12
|
+
constructor(binding) {
|
|
13
|
+
this.binding = binding;
|
|
14
|
+
}
|
|
15
|
+
async kv() {
|
|
16
|
+
const env = await getCloudflareRuntimeEnv();
|
|
17
|
+
const candidate = env?.[this.binding];
|
|
18
|
+
if (!candidate || typeof candidate !== "object")
|
|
19
|
+
return null;
|
|
20
|
+
const kv = candidate;
|
|
21
|
+
if (typeof kv.get !== "function" || typeof kv.put !== "function")
|
|
22
|
+
return null;
|
|
23
|
+
return candidate;
|
|
24
|
+
}
|
|
25
|
+
async read(sessionId) {
|
|
26
|
+
const kv = await this.kv();
|
|
27
|
+
if (!kv)
|
|
28
|
+
return 0;
|
|
29
|
+
const raw = await kv.get(`session/${sessionId}/__bytes__`, "json");
|
|
30
|
+
return typeof raw === "number" && raw >= 0 ? raw : 0;
|
|
31
|
+
}
|
|
32
|
+
async write(sessionId, used) {
|
|
33
|
+
const kv = await this.kv();
|
|
34
|
+
if (!kv)
|
|
35
|
+
return;
|
|
36
|
+
await kv.put(`session/${sessionId}/__bytes__`, JSON.stringify(used), { expirationTtl: QUOTA_TTL_SECONDS });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function getBucket(binding) {
|
|
40
|
+
const env = await getCloudflareRuntimeEnv();
|
|
41
|
+
const candidate = env?.[binding];
|
|
42
|
+
if (!candidate || typeof candidate !== "object")
|
|
43
|
+
return null;
|
|
44
|
+
const bucket = candidate;
|
|
45
|
+
if (typeof bucket.put !== "function")
|
|
46
|
+
return null;
|
|
47
|
+
return candidate;
|
|
48
|
+
}
|
|
49
|
+
async function resolvePublicBaseUrl(configured) {
|
|
50
|
+
if (configured)
|
|
51
|
+
return configured;
|
|
52
|
+
const env = await getCloudflareRuntimeEnv();
|
|
53
|
+
const raw = env?.R2_PUBLIC_DOMAIN;
|
|
54
|
+
if (typeof raw !== "string" || raw.trim().length === 0) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const trimmed = raw.trim().replace(/\/$/, "");
|
|
58
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
|
|
59
|
+
return trimmed;
|
|
60
|
+
}
|
|
61
|
+
return `https://${trimmed}`;
|
|
62
|
+
}
|
|
63
|
+
export class R2UploadHandler {
|
|
64
|
+
binding;
|
|
65
|
+
publicBaseUrl;
|
|
66
|
+
devServePath;
|
|
67
|
+
quotaBinding;
|
|
68
|
+
sandboxPerFileBytes;
|
|
69
|
+
sandboxPerSessionBytes;
|
|
70
|
+
constructor(options = {}) {
|
|
71
|
+
this.binding = options.binding ?? "CMS_R2";
|
|
72
|
+
this.publicBaseUrl = options.publicBaseUrl?.replace(/\/$/, "") ?? null;
|
|
73
|
+
this.devServePath = options.devServePath ?? "/api/cms/image";
|
|
74
|
+
this.quotaBinding = options.quotaBinding ?? "CMS_KV";
|
|
75
|
+
this.sandboxPerFileBytes = options.sandboxPerFileBytes ?? 5 * 1024 * 1024;
|
|
76
|
+
this.sandboxPerSessionBytes = options.sandboxPerSessionBytes ?? 25 * 1024 * 1024;
|
|
77
|
+
}
|
|
78
|
+
async makeSessionWrapper(_sessionId) {
|
|
79
|
+
return new QuotaUploadHandler({
|
|
80
|
+
inner: this,
|
|
81
|
+
counter: new KvQuotaCounter(this.quotaBinding),
|
|
82
|
+
perFileBytes: this.sandboxPerFileBytes,
|
|
83
|
+
perSessionBytes: this.sandboxPerSessionBytes,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
async upload(file, ctx) {
|
|
87
|
+
// Buffer + magic-byte verify before touching R2 so a spoofed
|
|
88
|
+
// Content-Type can't land an HTML/SVG payload under an image/* MIME.
|
|
89
|
+
const { kind, bytes } = await readAndValidateImage(file);
|
|
90
|
+
const bucket = await getBucket(this.binding);
|
|
91
|
+
if (!bucket) {
|
|
92
|
+
throw new Error(`[caretcms] Cloudflare R2 binding "${this.binding}" is not available.`);
|
|
93
|
+
}
|
|
94
|
+
const timestamp = Date.now().toString(36);
|
|
95
|
+
// Discard the client-supplied extension and re-derive from verified bytes.
|
|
96
|
+
// Prevents `evil.html.jpg`-style double extensions from reaching the key.
|
|
97
|
+
const safeName = sanitizeImageBaseName(file.name) || `upload-${timestamp}`;
|
|
98
|
+
const ext = IMAGE_KIND_TO_EXT[kind];
|
|
99
|
+
const verifiedContentType = KIND_TO_CONTENT_TYPE[kind];
|
|
100
|
+
const prefix = ctx?.sessionId ? `session/${ctx.sessionId}/` : "";
|
|
101
|
+
const key = `${prefix}${crypto.randomUUID()}-${safeName}.${ext}`;
|
|
102
|
+
await bucket.put(key, bytes, {
|
|
103
|
+
httpMetadata: { contentType: verifiedContentType },
|
|
104
|
+
});
|
|
105
|
+
const publicBaseUrl = await resolvePublicBaseUrl(this.publicBaseUrl);
|
|
106
|
+
if (import.meta.env.DEV || !publicBaseUrl) {
|
|
107
|
+
return { url: `${this.devServePath}/${key}` };
|
|
108
|
+
}
|
|
109
|
+
return { url: `${publicBaseUrl}/${key}` };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=r2-upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"r2-upload.js","sourceRoot":"","sources":["../../src/adapters/r2-upload.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { CloudflareKvStorageAdapter, type CloudflareKvStorageOptions, } from "./adapters/kv-storage.js";
|
|
2
|
+
export { R2UploadHandler, type R2UploadHandlerOptions, } from "./adapters/r2-upload.js";
|
|
3
|
+
export { cloudflareStorage, cloudflareStorageProvider } from "./providers/storage.js";
|
|
4
|
+
export { r2Uploads, r2UploadsProvider } from "./providers/uploads.js";
|
|
5
|
+
export { getCloudflareRuntimeEnv, type CloudflareRuntimeEnv } from "./runtime/env.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,KAAK,0BAA0B,GAChC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,GAC5B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { CloudflareKvStorageAdapter, } from "./adapters/kv-storage.js";
|
|
2
|
+
export { R2UploadHandler, } from "./adapters/r2-upload.js";
|
|
3
|
+
export { cloudflareStorage, cloudflareStorageProvider } from "./providers/storage.js";
|
|
4
|
+
export { r2Uploads, r2UploadsProvider } from "./providers/uploads.js";
|
|
5
|
+
export { getCloudflareRuntimeEnv } from "./runtime/env.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,GAE3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,eAAe,GAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAA6B,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type CaretStorageProvider } from "@caretcms/core";
|
|
2
|
+
import { CloudflareKvStorageAdapter, type CloudflareKvStorageOptions } from "../adapters/kv-storage.js";
|
|
3
|
+
export declare function cloudflareStorageProvider(options?: CloudflareKvStorageOptions): CloudflareKvStorageAdapter;
|
|
4
|
+
export declare function cloudflareStorage(options?: CloudflareKvStorageOptions): CaretStorageProvider;
|
|
5
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/providers/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,KAAK,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAExG,wBAAgB,yBAAyB,CACvC,OAAO,CAAC,EAAE,0BAA0B,GACnC,0BAA0B,CAE5B;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,CAAC,EAAE,0BAA0B,GACnC,oBAAoB,CAMtB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineStorageProvider } from "@caretcms/core";
|
|
2
|
+
import { CloudflareKvStorageAdapter } from "../adapters/kv-storage.js";
|
|
3
|
+
export function cloudflareStorageProvider(options) {
|
|
4
|
+
return new CloudflareKvStorageAdapter(options);
|
|
5
|
+
}
|
|
6
|
+
export function cloudflareStorage(options) {
|
|
7
|
+
return defineStorageProvider({
|
|
8
|
+
entrypoint: "@caretcms/cloudflare/providers/storage",
|
|
9
|
+
exportName: "cloudflareStorageProvider",
|
|
10
|
+
options,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/providers/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAA6B,MAAM,gBAAgB,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAmC,MAAM,2BAA2B,CAAC;AAExG,MAAM,UAAU,yBAAyB,CACvC,OAAoC;IAEpC,OAAO,IAAI,0BAA0B,CAAC,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,OAAoC;IAEpC,OAAO,qBAAqB,CAAC;QAC3B,UAAU,EAAE,wCAAwC;QACpD,UAAU,EAAE,2BAA2B;QACvC,OAAO;KACR,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type CaretUploadProvider } from "@caretcms/core";
|
|
2
|
+
import { R2UploadHandler, type R2UploadHandlerOptions } from "../adapters/r2-upload.js";
|
|
3
|
+
export declare function r2UploadsProvider(options?: R2UploadHandlerOptions): R2UploadHandler;
|
|
4
|
+
export declare function r2Uploads(options?: R2UploadHandlerOptions): CaretUploadProvider;
|
|
5
|
+
//# sourceMappingURL=uploads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["../../src/providers/uploads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAExF,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,eAAe,CAEnF;AAED,wBAAgB,SAAS,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,mBAAmB,CAM/E"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineUploadProvider } from "@caretcms/core";
|
|
2
|
+
import { R2UploadHandler } from "../adapters/r2-upload.js";
|
|
3
|
+
export function r2UploadsProvider(options) {
|
|
4
|
+
return new R2UploadHandler(options);
|
|
5
|
+
}
|
|
6
|
+
export function r2Uploads(options) {
|
|
7
|
+
return defineUploadProvider({
|
|
8
|
+
entrypoint: "@caretcms/cloudflare/providers/uploads",
|
|
9
|
+
exportName: "r2UploadsProvider",
|
|
10
|
+
options,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=uploads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploads.js","sourceRoot":"","sources":["../../src/providers/uploads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAA4B,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,eAAe,EAA+B,MAAM,0BAA0B,CAAC;AAExF,MAAM,UAAU,iBAAiB,CAAC,OAAgC;IAChE,OAAO,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAgC;IACxD,OAAO,oBAAoB,CAAC;QAC1B,UAAU,EAAE,wCAAwC;QACpD,UAAU,EAAE,mBAAmB;QAC/B,OAAO;KACR,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/runtime/env.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3D,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAQpF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/runtime/env.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAI,GAAyC,CAAC,GAAG,CAAC;QAC3D,OAAO,GAAG,IAAI,IAAI,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@caretcms/cloudflare",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Cloudflare-native storage (KV) and uploads (R2) adapters for CaretCMS.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"astro",
|
|
9
|
+
"cms",
|
|
10
|
+
"cloudflare",
|
|
11
|
+
"workers",
|
|
12
|
+
"kv",
|
|
13
|
+
"r2",
|
|
14
|
+
"caret",
|
|
15
|
+
"storage-adapter"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://github.com/web-stacked/caretcms/tree/main/packages/cloudflare#readme",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/web-stacked/caretcms.git",
|
|
21
|
+
"directory": "packages/cloudflare"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/web-stacked/caretcms/issues"
|
|
25
|
+
},
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./providers/storage": {
|
|
34
|
+
"types": "./dist/providers/storage.d.ts",
|
|
35
|
+
"import": "./dist/providers/storage.js"
|
|
36
|
+
},
|
|
37
|
+
"./providers/uploads": {
|
|
38
|
+
"types": "./dist/providers/uploads.d.ts",
|
|
39
|
+
"import": "./dist/providers/uploads.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc -p tsconfig.build.json",
|
|
47
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
48
|
+
"clean": "rm -rf dist",
|
|
49
|
+
"prepublishOnly": "node scripts/check-version.mjs && npm run clean && npm run build"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@caretcms/core": "^0.1.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/node": "25.6.0",
|
|
59
|
+
"typescript": "6.0.3"
|
|
60
|
+
}
|
|
61
|
+
}
|