@syncular/server-cloudflare 0.0.6-89 → 0.0.6-92

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.
@@ -1 +1 @@
1
- {"version":3,"file":"durable-object.js","sourceRoot":"","sources":["../src/durable-object.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"durable-object.js","sourceRoot":"","sources":["../src/durable-object.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -8,11 +8,15 @@
8
8
  * Blob storage:
9
9
  * - R2 native: `@syncular/server-cloudflare/r2`
10
10
  *
11
+ * Scope cache:
12
+ * - Durable Object cache backend: `@syncular/server-cloudflare/scope-cache`
13
+ *
11
14
  * Dialect is user-provided:
12
15
  * - D1 + SQLite: `@syncular/dialect-d1` + `@syncular/server-dialect-sqlite`
13
16
  * - Neon + Postgres: `@syncular/dialect-neon` + `@syncular/server-dialect-postgres`
14
17
  */
15
18
  export * from './durable-object';
16
19
  export * from './r2';
20
+ export * from './scope-cache';
17
21
  export * from './worker';
18
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,MAAM,CAAC;AACrB,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,MAAM,CAAC;AACrB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -8,11 +8,15 @@
8
8
  * Blob storage:
9
9
  * - R2 native: `@syncular/server-cloudflare/r2`
10
10
  *
11
+ * Scope cache:
12
+ * - Durable Object cache backend: `@syncular/server-cloudflare/scope-cache`
13
+ *
11
14
  * Dialect is user-provided:
12
15
  * - D1 + SQLite: `@syncular/dialect-d1` + `@syncular/server-dialect-sqlite`
13
16
  * - Neon + Postgres: `@syncular/dialect-neon` + `@syncular/server-dialect-postgres`
14
17
  */
15
18
  export * from './durable-object.js';
16
19
  export * from './r2.js';
20
+ export * from './scope-cache.js';
17
21
  export * from './worker.js';
18
22
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,MAAM,CAAC;AACrB,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,MAAM,CAAC;AACrB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Durable Object-backed scope cache for @syncular/server.
3
+ *
4
+ * This module provides two parts:
5
+ * 1) `createDurableObjectScopeCache()` - cache backend to pass to createSyncServer/createSyncRoutes
6
+ * 2) `ScopeCacheDurableObject` - Durable Object class that stores scope entries in DO storage
7
+ */
8
+ type ScopeValues = Record<string, string | string[]>;
9
+ interface ScopeCacheContext {
10
+ db: object;
11
+ auth: {
12
+ actorId: string;
13
+ partitionId?: string;
14
+ };
15
+ table: string;
16
+ cacheKey: string;
17
+ }
18
+ interface ScopeCacheSetContext extends ScopeCacheContext {
19
+ scopes: ScopeValues;
20
+ }
21
+ interface ScopeCacheBackend {
22
+ name: string;
23
+ get(args: ScopeCacheContext): Promise<ScopeValues | null>;
24
+ set(args: ScopeCacheSetContext): Promise<void>;
25
+ delete?(args: ScopeCacheContext): Promise<void>;
26
+ }
27
+ interface ScopeCacheLookup {
28
+ cacheKey: string;
29
+ partitionId: string;
30
+ actorId: string;
31
+ table: string;
32
+ }
33
+ /**
34
+ * Durable Object for scope cache entries.
35
+ *
36
+ * Bind this class in your Worker as a separate DO namespace.
37
+ */
38
+ export declare class ScopeCacheDurableObject {
39
+ private readonly state;
40
+ constructor(state: DurableObjectState, _env: object);
41
+ fetch(request: Request): Promise<Response>;
42
+ }
43
+ export interface DurableObjectScopeCacheOptions {
44
+ namespace: DurableObjectNamespace;
45
+ ttlMs?: number;
46
+ path?: string;
47
+ getStubId?: (namespace: DurableObjectNamespace, lookup: ScopeCacheLookup) => DurableObjectId;
48
+ }
49
+ /**
50
+ * Create a scope cache backend that reads/writes through a Durable Object.
51
+ */
52
+ export declare function createDurableObjectScopeCache(options: DurableObjectScopeCacheOptions): ScopeCacheBackend;
53
+ export {};
54
+ //# sourceMappingURL=scope-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-cache.d.ts","sourceRoot":"","sources":["../src/scope-cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;AAErD,UAAU,iBAAiB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,oBAAqB,SAAQ,iBAAiB;IACtD,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC1D,GAAG,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,CAAC,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAOD,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AA+HD;;;;GAIG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAE3C,YAAY,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAElD;IAEK,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0C/C;CACF;AAED,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,sBAAsB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,CACV,SAAS,EAAE,sBAAsB,EACjC,MAAM,EAAE,gBAAgB,KACrB,eAAe,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,8BAA8B,GACtC,iBAAiB,CAwFnB"}
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Durable Object-backed scope cache for @syncular/server.
3
+ *
4
+ * This module provides two parts:
5
+ * 1) `createDurableObjectScopeCache()` - cache backend to pass to createSyncServer/createSyncRoutes
6
+ * 2) `ScopeCacheDurableObject` - Durable Object class that stores scope entries in DO storage
7
+ */
8
+ const DEFAULT_SCOPE_CACHE_TTL_MS = 60_000;
9
+ const DEFAULT_SCOPE_CACHE_DO_NAME = 'syncular-scope-cache';
10
+ const DEFAULT_SCOPE_CACHE_PATH = '/scope-cache';
11
+ const JSON_HEADERS = { 'content-type': 'application/json' };
12
+ function cloneScopeValues(scopes) {
13
+ const cloned = {};
14
+ for (const [key, value] of Object.entries(scopes)) {
15
+ if (typeof value === 'string') {
16
+ cloned[key] = value;
17
+ continue;
18
+ }
19
+ cloned[key] = [...value];
20
+ }
21
+ return cloned;
22
+ }
23
+ function isScopeValues(value) {
24
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
25
+ return false;
26
+ }
27
+ for (const scopeValue of Object.values(value)) {
28
+ if (typeof scopeValue === 'string') {
29
+ continue;
30
+ }
31
+ if (Array.isArray(scopeValue) &&
32
+ scopeValue.every((entry) => typeof entry === 'string')) {
33
+ continue;
34
+ }
35
+ return false;
36
+ }
37
+ return true;
38
+ }
39
+ function parseJsonObject(value) {
40
+ let parsed;
41
+ try {
42
+ parsed = JSON.parse(value);
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
48
+ return null;
49
+ }
50
+ const out = {};
51
+ for (const [key, entry] of Object.entries(parsed)) {
52
+ out[key] = entry;
53
+ }
54
+ return out;
55
+ }
56
+ async function parseRequestBody(request) {
57
+ let body;
58
+ try {
59
+ body = await request.text();
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ const parsed = parseJsonObject(body);
65
+ if (!parsed) {
66
+ return null;
67
+ }
68
+ const action = parsed.action;
69
+ const cacheKey = parsed.cacheKey;
70
+ if (typeof action !== 'string' || typeof cacheKey !== 'string') {
71
+ return null;
72
+ }
73
+ if (action === 'get') {
74
+ return { action: 'get', cacheKey };
75
+ }
76
+ if (action === 'delete') {
77
+ return { action: 'delete', cacheKey };
78
+ }
79
+ if (action === 'set') {
80
+ const ttlMs = parsed.ttlMs;
81
+ const scopes = parsed.scopes;
82
+ if (typeof ttlMs !== 'number' ||
83
+ Number.isNaN(ttlMs) ||
84
+ !Number.isFinite(ttlMs)) {
85
+ return null;
86
+ }
87
+ if (!isScopeValues(scopes)) {
88
+ return null;
89
+ }
90
+ return {
91
+ action: 'set',
92
+ cacheKey,
93
+ scopes: cloneScopeValues(scopes),
94
+ ttlMs,
95
+ };
96
+ }
97
+ return null;
98
+ }
99
+ /**
100
+ * Durable Object for scope cache entries.
101
+ *
102
+ * Bind this class in your Worker as a separate DO namespace.
103
+ */
104
+ export class ScopeCacheDurableObject {
105
+ state;
106
+ constructor(state, _env) {
107
+ this.state = state;
108
+ }
109
+ async fetch(request) {
110
+ if (request.method !== 'POST') {
111
+ return new Response('Method not allowed', { status: 405 });
112
+ }
113
+ const payload = await parseRequestBody(request);
114
+ if (!payload) {
115
+ return new Response('Invalid scope cache request', { status: 400 });
116
+ }
117
+ if (payload.action === 'get') {
118
+ const entry = await this.state.storage.get(payload.cacheKey);
119
+ if (!entry) {
120
+ return Response.json({ scopes: null });
121
+ }
122
+ if (entry.expiresAt <= Date.now()) {
123
+ await this.state.storage.delete(payload.cacheKey);
124
+ return Response.json({ scopes: null });
125
+ }
126
+ return Response.json({ scopes: cloneScopeValues(entry.scopes) });
127
+ }
128
+ if (payload.action === 'set') {
129
+ if (payload.ttlMs <= 0) {
130
+ await this.state.storage.delete(payload.cacheKey);
131
+ return Response.json({ ok: true });
132
+ }
133
+ await this.state.storage.put(payload.cacheKey, {
134
+ scopes: cloneScopeValues(payload.scopes),
135
+ expiresAt: Date.now() + payload.ttlMs,
136
+ });
137
+ return Response.json({ ok: true });
138
+ }
139
+ await this.state.storage.delete(payload.cacheKey);
140
+ return Response.json({ ok: true });
141
+ }
142
+ }
143
+ /**
144
+ * Create a scope cache backend that reads/writes through a Durable Object.
145
+ */
146
+ export function createDurableObjectScopeCache(options) {
147
+ const ttlMs = options.ttlMs ?? DEFAULT_SCOPE_CACHE_TTL_MS;
148
+ const path = options.path ?? DEFAULT_SCOPE_CACHE_PATH;
149
+ const getStubId = options.getStubId ??
150
+ ((namespace) => namespace.idFromName(DEFAULT_SCOPE_CACHE_DO_NAME));
151
+ async function callDurableObject(lookup, body) {
152
+ const id = getStubId(options.namespace, lookup);
153
+ const stub = options.namespace.get(id);
154
+ const response = await stub.fetch(`https://scope-cache${path}`, {
155
+ method: 'POST',
156
+ headers: JSON_HEADERS,
157
+ body: JSON.stringify(body),
158
+ });
159
+ if (!response.ok) {
160
+ throw new Error(`Scope cache durable object request failed: ${response.status}`);
161
+ }
162
+ const parsed = parseJsonObject(await response.text());
163
+ if (!parsed) {
164
+ throw new Error('Scope cache durable object response was not JSON');
165
+ }
166
+ return parsed;
167
+ }
168
+ return {
169
+ name: 'durable-object',
170
+ async get(args) {
171
+ const lookup = {
172
+ cacheKey: args.cacheKey,
173
+ partitionId: args.auth.partitionId ?? 'default',
174
+ actorId: args.auth.actorId,
175
+ table: args.table,
176
+ };
177
+ const response = await callDurableObject(lookup, {
178
+ action: 'get',
179
+ cacheKey: args.cacheKey,
180
+ });
181
+ const scopes = response.scopes;
182
+ if (scopes === null || scopes === undefined) {
183
+ return null;
184
+ }
185
+ if (!isScopeValues(scopes)) {
186
+ return null;
187
+ }
188
+ return cloneScopeValues(scopes);
189
+ },
190
+ async set(args) {
191
+ const lookup = {
192
+ cacheKey: args.cacheKey,
193
+ partitionId: args.auth.partitionId ?? 'default',
194
+ actorId: args.auth.actorId,
195
+ table: args.table,
196
+ };
197
+ await callDurableObject(lookup, {
198
+ action: 'set',
199
+ cacheKey: args.cacheKey,
200
+ scopes: cloneScopeValues(args.scopes),
201
+ ttlMs,
202
+ });
203
+ },
204
+ async delete(args) {
205
+ const lookup = {
206
+ cacheKey: args.cacheKey,
207
+ partitionId: args.auth.partitionId ?? 'default',
208
+ actorId: args.auth.actorId,
209
+ table: args.table,
210
+ };
211
+ await callDurableObject(lookup, {
212
+ action: 'delete',
213
+ cacheKey: args.cacheKey,
214
+ });
215
+ },
216
+ };
217
+ }
218
+ //# sourceMappingURL=scope-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-cache.js","sourceRoot":"","sources":["../src/scope-cache.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/server-cloudflare",
3
- "version": "0.0.6-89",
3
+ "version": "0.0.6-92",
4
4
  "description": "Cloudflare Workers adapter for the Syncular server",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Benjamin Kniffler",
@@ -56,6 +56,13 @@
56
56
  "types": "./dist/r2.d.ts",
57
57
  "default": "./dist/r2.js"
58
58
  }
59
+ },
60
+ "./scope-cache": {
61
+ "bun": "./src/scope-cache.ts",
62
+ "import": {
63
+ "types": "./dist/scope-cache.d.ts",
64
+ "default": "./dist/scope-cache.js"
65
+ }
59
66
  }
60
67
  },
61
68
  "scripts": {
package/src/index.ts CHANGED
@@ -8,6 +8,9 @@
8
8
  * Blob storage:
9
9
  * - R2 native: `@syncular/server-cloudflare/r2`
10
10
  *
11
+ * Scope cache:
12
+ * - Durable Object cache backend: `@syncular/server-cloudflare/scope-cache`
13
+ *
11
14
  * Dialect is user-provided:
12
15
  * - D1 + SQLite: `@syncular/dialect-d1` + `@syncular/server-dialect-sqlite`
13
16
  * - Neon + Postgres: `@syncular/dialect-neon` + `@syncular/server-dialect-postgres`
@@ -15,4 +18,5 @@
15
18
 
16
19
  export * from './durable-object';
17
20
  export * from './r2';
21
+ export * from './scope-cache';
18
22
  export * from './worker';
@@ -0,0 +1,329 @@
1
+ /**
2
+ * Durable Object-backed scope cache for @syncular/server.
3
+ *
4
+ * This module provides two parts:
5
+ * 1) `createDurableObjectScopeCache()` - cache backend to pass to createSyncServer/createSyncRoutes
6
+ * 2) `ScopeCacheDurableObject` - Durable Object class that stores scope entries in DO storage
7
+ */
8
+
9
+ type ScopeValues = Record<string, string | string[]>;
10
+
11
+ interface ScopeCacheContext {
12
+ db: object;
13
+ auth: {
14
+ actorId: string;
15
+ partitionId?: string;
16
+ };
17
+ table: string;
18
+ cacheKey: string;
19
+ }
20
+
21
+ interface ScopeCacheSetContext extends ScopeCacheContext {
22
+ scopes: ScopeValues;
23
+ }
24
+
25
+ interface ScopeCacheBackend {
26
+ name: string;
27
+ get(args: ScopeCacheContext): Promise<ScopeValues | null>;
28
+ set(args: ScopeCacheSetContext): Promise<void>;
29
+ delete?(args: ScopeCacheContext): Promise<void>;
30
+ }
31
+
32
+ const DEFAULT_SCOPE_CACHE_TTL_MS = 60_000;
33
+ const DEFAULT_SCOPE_CACHE_DO_NAME = 'syncular-scope-cache';
34
+ const DEFAULT_SCOPE_CACHE_PATH = '/scope-cache';
35
+ const JSON_HEADERS = { 'content-type': 'application/json' };
36
+
37
+ interface ScopeCacheLookup {
38
+ cacheKey: string;
39
+ partitionId: string;
40
+ actorId: string;
41
+ table: string;
42
+ }
43
+
44
+ type ScopeCacheRequestBody =
45
+ | {
46
+ action: 'get';
47
+ cacheKey: string;
48
+ }
49
+ | {
50
+ action: 'set';
51
+ cacheKey: string;
52
+ scopes: ScopeValues;
53
+ ttlMs: number;
54
+ }
55
+ | {
56
+ action: 'delete';
57
+ cacheKey: string;
58
+ };
59
+
60
+ function cloneScopeValues(scopes: ScopeValues): ScopeValues {
61
+ const cloned: ScopeValues = {};
62
+ for (const [key, value] of Object.entries(scopes)) {
63
+ if (typeof value === 'string') {
64
+ cloned[key] = value;
65
+ continue;
66
+ }
67
+ cloned[key] = [...value];
68
+ }
69
+ return cloned;
70
+ }
71
+
72
+ function isScopeValues(value: unknown): value is ScopeValues {
73
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
74
+ return false;
75
+ }
76
+
77
+ for (const scopeValue of Object.values(value)) {
78
+ if (typeof scopeValue === 'string') {
79
+ continue;
80
+ }
81
+ if (
82
+ Array.isArray(scopeValue) &&
83
+ scopeValue.every((entry) => typeof entry === 'string')
84
+ ) {
85
+ continue;
86
+ }
87
+ return false;
88
+ }
89
+ return true;
90
+ }
91
+
92
+ function parseJsonObject(value: string): Record<string, unknown> | null {
93
+ let parsed: unknown;
94
+ try {
95
+ parsed = JSON.parse(value);
96
+ } catch {
97
+ return null;
98
+ }
99
+
100
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
101
+ return null;
102
+ }
103
+
104
+ const out: Record<string, unknown> = {};
105
+ for (const [key, entry] of Object.entries(parsed)) {
106
+ out[key] = entry;
107
+ }
108
+ return out;
109
+ }
110
+
111
+ async function parseRequestBody(
112
+ request: Request
113
+ ): Promise<ScopeCacheRequestBody | null> {
114
+ let body: string;
115
+ try {
116
+ body = await request.text();
117
+ } catch {
118
+ return null;
119
+ }
120
+
121
+ const parsed = parseJsonObject(body);
122
+ if (!parsed) {
123
+ return null;
124
+ }
125
+
126
+ const action = parsed.action;
127
+ const cacheKey = parsed.cacheKey;
128
+ if (typeof action !== 'string' || typeof cacheKey !== 'string') {
129
+ return null;
130
+ }
131
+
132
+ if (action === 'get') {
133
+ return { action: 'get', cacheKey };
134
+ }
135
+
136
+ if (action === 'delete') {
137
+ return { action: 'delete', cacheKey };
138
+ }
139
+
140
+ if (action === 'set') {
141
+ const ttlMs = parsed.ttlMs;
142
+ const scopes = parsed.scopes;
143
+ if (
144
+ typeof ttlMs !== 'number' ||
145
+ Number.isNaN(ttlMs) ||
146
+ !Number.isFinite(ttlMs)
147
+ ) {
148
+ return null;
149
+ }
150
+ if (!isScopeValues(scopes)) {
151
+ return null;
152
+ }
153
+ return {
154
+ action: 'set',
155
+ cacheKey,
156
+ scopes: cloneScopeValues(scopes),
157
+ ttlMs,
158
+ };
159
+ }
160
+
161
+ return null;
162
+ }
163
+
164
+ interface StoredScopeCacheValue {
165
+ scopes: ScopeValues;
166
+ expiresAt: number;
167
+ }
168
+
169
+ /**
170
+ * Durable Object for scope cache entries.
171
+ *
172
+ * Bind this class in your Worker as a separate DO namespace.
173
+ */
174
+ export class ScopeCacheDurableObject {
175
+ private readonly state: DurableObjectState;
176
+
177
+ constructor(state: DurableObjectState, _env: object) {
178
+ this.state = state;
179
+ }
180
+
181
+ async fetch(request: Request): Promise<Response> {
182
+ if (request.method !== 'POST') {
183
+ return new Response('Method not allowed', { status: 405 });
184
+ }
185
+
186
+ const payload = await parseRequestBody(request);
187
+ if (!payload) {
188
+ return new Response('Invalid scope cache request', { status: 400 });
189
+ }
190
+
191
+ if (payload.action === 'get') {
192
+ const entry = await this.state.storage.get<StoredScopeCacheValue>(
193
+ payload.cacheKey
194
+ );
195
+ if (!entry) {
196
+ return Response.json({ scopes: null });
197
+ }
198
+
199
+ if (entry.expiresAt <= Date.now()) {
200
+ await this.state.storage.delete(payload.cacheKey);
201
+ return Response.json({ scopes: null });
202
+ }
203
+
204
+ return Response.json({ scopes: cloneScopeValues(entry.scopes) });
205
+ }
206
+
207
+ if (payload.action === 'set') {
208
+ if (payload.ttlMs <= 0) {
209
+ await this.state.storage.delete(payload.cacheKey);
210
+ return Response.json({ ok: true });
211
+ }
212
+
213
+ await this.state.storage.put(payload.cacheKey, {
214
+ scopes: cloneScopeValues(payload.scopes),
215
+ expiresAt: Date.now() + payload.ttlMs,
216
+ } satisfies StoredScopeCacheValue);
217
+
218
+ return Response.json({ ok: true });
219
+ }
220
+
221
+ await this.state.storage.delete(payload.cacheKey);
222
+ return Response.json({ ok: true });
223
+ }
224
+ }
225
+
226
+ export interface DurableObjectScopeCacheOptions {
227
+ namespace: DurableObjectNamespace;
228
+ ttlMs?: number;
229
+ path?: string;
230
+ getStubId?: (
231
+ namespace: DurableObjectNamespace,
232
+ lookup: ScopeCacheLookup
233
+ ) => DurableObjectId;
234
+ }
235
+
236
+ /**
237
+ * Create a scope cache backend that reads/writes through a Durable Object.
238
+ */
239
+ export function createDurableObjectScopeCache(
240
+ options: DurableObjectScopeCacheOptions
241
+ ): ScopeCacheBackend {
242
+ const ttlMs = options.ttlMs ?? DEFAULT_SCOPE_CACHE_TTL_MS;
243
+ const path = options.path ?? DEFAULT_SCOPE_CACHE_PATH;
244
+ const getStubId =
245
+ options.getStubId ??
246
+ ((namespace: DurableObjectNamespace) =>
247
+ namespace.idFromName(DEFAULT_SCOPE_CACHE_DO_NAME));
248
+
249
+ async function callDurableObject(
250
+ lookup: ScopeCacheLookup,
251
+ body: ScopeCacheRequestBody
252
+ ): Promise<Record<string, unknown>> {
253
+ const id = getStubId(options.namespace, lookup);
254
+ const stub = options.namespace.get(id);
255
+ const response = await stub.fetch(`https://scope-cache${path}`, {
256
+ method: 'POST',
257
+ headers: JSON_HEADERS,
258
+ body: JSON.stringify(body),
259
+ });
260
+
261
+ if (!response.ok) {
262
+ throw new Error(
263
+ `Scope cache durable object request failed: ${response.status}`
264
+ );
265
+ }
266
+
267
+ const parsed = parseJsonObject(await response.text());
268
+ if (!parsed) {
269
+ throw new Error('Scope cache durable object response was not JSON');
270
+ }
271
+
272
+ return parsed;
273
+ }
274
+
275
+ return {
276
+ name: 'durable-object',
277
+ async get(args) {
278
+ const lookup: ScopeCacheLookup = {
279
+ cacheKey: args.cacheKey,
280
+ partitionId: args.auth.partitionId ?? 'default',
281
+ actorId: args.auth.actorId,
282
+ table: args.table,
283
+ };
284
+
285
+ const response = await callDurableObject(lookup, {
286
+ action: 'get',
287
+ cacheKey: args.cacheKey,
288
+ });
289
+ const scopes = response.scopes;
290
+ if (scopes === null || scopes === undefined) {
291
+ return null;
292
+ }
293
+
294
+ if (!isScopeValues(scopes)) {
295
+ return null;
296
+ }
297
+
298
+ return cloneScopeValues(scopes);
299
+ },
300
+ async set(args) {
301
+ const lookup: ScopeCacheLookup = {
302
+ cacheKey: args.cacheKey,
303
+ partitionId: args.auth.partitionId ?? 'default',
304
+ actorId: args.auth.actorId,
305
+ table: args.table,
306
+ };
307
+
308
+ await callDurableObject(lookup, {
309
+ action: 'set',
310
+ cacheKey: args.cacheKey,
311
+ scopes: cloneScopeValues(args.scopes),
312
+ ttlMs,
313
+ });
314
+ },
315
+ async delete(args) {
316
+ const lookup: ScopeCacheLookup = {
317
+ cacheKey: args.cacheKey,
318
+ partitionId: args.auth.partitionId ?? 'default',
319
+ actorId: args.auth.actorId,
320
+ table: args.table,
321
+ };
322
+
323
+ await callDurableObject(lookup, {
324
+ action: 'delete',
325
+ cacheKey: args.cacheKey,
326
+ });
327
+ },
328
+ };
329
+ }