@ontrails/cloudflare 1.0.0-beta.39 → 1.0.0-beta.41
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/CHANGELOG.md +41 -0
- package/README.md +160 -8
- package/package.json +15 -6
- package/src/d1/index.ts +1087 -0
- package/src/env.ts +60 -26
- package/src/index.ts +55 -0
- package/src/kv/index.ts +1 -1
- package/src/queues/index.ts +746 -0
- package/src/r2/index.ts +736 -0
- package/src/workers/index.ts +70 -2
package/src/env.ts
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Overrides are re-resolved whenever a new `env` object arrives, and core
|
|
12
12
|
* resolves overrides before its singleton resource cache, so no resource
|
|
13
|
-
* instance can capture a stale env. Every Cloudflare subpath
|
|
14
|
-
*
|
|
13
|
+
* instance can capture a stale env. Every Cloudflare service subpath consumes
|
|
14
|
+
* this one seam.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import {
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
matchesTrailPattern,
|
|
20
20
|
Result,
|
|
21
21
|
filterSurfaceTrails,
|
|
22
|
+
isLiveTrailVersionEntry,
|
|
22
23
|
} from '@ontrails/core';
|
|
23
24
|
import type {
|
|
24
25
|
AnyResource,
|
|
@@ -31,7 +32,8 @@ import type {
|
|
|
31
32
|
/**
|
|
32
33
|
* The ambient Worker environment: bindings keyed by their wrangler-configured
|
|
33
34
|
* names. Values are runtime binding objects (KV namespaces, D1 databases,
|
|
34
|
-
* queues), so they are typed as `unknown` and narrowed by each
|
|
35
|
+
* R2 buckets, queues), so they are typed as `unknown` and narrowed by each
|
|
36
|
+
* subpath.
|
|
35
37
|
*/
|
|
36
38
|
export type WorkersEnv = Readonly<Record<string, unknown>>;
|
|
37
39
|
|
|
@@ -110,6 +112,10 @@ export interface BuildEnvResourceOverridesOptions extends Pick<
|
|
|
110
112
|
> {
|
|
111
113
|
/** Resource IDs already provided explicitly; env resolution skips them. */
|
|
112
114
|
readonly except?: readonly string[] | undefined;
|
|
115
|
+
/** Worker entrypoint whose reachable resources should be materialized. */
|
|
116
|
+
readonly entrypoint?: 'fetch' | 'queue' | undefined;
|
|
117
|
+
/** Physical queue delivered to the current queue entrypoint. */
|
|
118
|
+
readonly queue?: string | undefined;
|
|
113
119
|
}
|
|
114
120
|
|
|
115
121
|
const isInternalTrail = (
|
|
@@ -134,18 +140,25 @@ const passesIncludeFilter = (
|
|
|
134
140
|
matchesAnyPattern(trailId, include);
|
|
135
141
|
|
|
136
142
|
/**
|
|
137
|
-
* Mirror of
|
|
138
|
-
*
|
|
139
|
-
*
|
|
143
|
+
* Mirror of Worker activation eligibility for one entrypoint. Activation
|
|
144
|
+
* consumers are skipped by `filterSurfaceTrails`, so the bridge selects them
|
|
145
|
+
* explicitly without making fetch depend on queue-only resources.
|
|
140
146
|
*/
|
|
141
|
-
const
|
|
147
|
+
const isEligibleWorkerActivationTrail = (
|
|
142
148
|
graphTrail: Trail<unknown, unknown, unknown>,
|
|
143
149
|
options: BuildEnvResourceOverridesOptions
|
|
144
150
|
): boolean => {
|
|
145
|
-
const
|
|
146
|
-
(
|
|
151
|
+
const activationKind =
|
|
152
|
+
(options.entrypoint ?? 'fetch') === 'queue' ? 'queue' : 'webhook';
|
|
153
|
+
const hasWorkerActivationSource = graphTrail.activationSources.some(
|
|
154
|
+
(activation) =>
|
|
155
|
+
activation.source.kind === activationKind &&
|
|
156
|
+
(activationKind !== 'queue' ||
|
|
157
|
+
options.queue === undefined ||
|
|
158
|
+
(typeof activation.source.queue === 'string' &&
|
|
159
|
+
activation.source.queue.trim() === options.queue))
|
|
147
160
|
);
|
|
148
|
-
if (!
|
|
161
|
+
if (!hasWorkerActivationSource) {
|
|
149
162
|
return false;
|
|
150
163
|
}
|
|
151
164
|
if (
|
|
@@ -173,37 +186,58 @@ const collectSurfaceEligibleTrails = (
|
|
|
173
186
|
): readonly Trail<unknown, unknown, unknown>[] => {
|
|
174
187
|
const trails = graph.list();
|
|
175
188
|
const eligible = new Map<string, Trail<unknown, unknown, unknown>>();
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
189
|
+
if ((options.entrypoint ?? 'fetch') === 'fetch') {
|
|
190
|
+
const filtered = filterSurfaceTrails(trails, {
|
|
191
|
+
exclude: options.exclude,
|
|
192
|
+
include: options.include,
|
|
193
|
+
intent: options.intent,
|
|
194
|
+
});
|
|
195
|
+
for (const graphTrail of filtered) {
|
|
196
|
+
eligible.set(graphTrail.id, graphTrail);
|
|
197
|
+
}
|
|
183
198
|
}
|
|
184
199
|
for (const graphTrail of trails) {
|
|
185
200
|
if (
|
|
186
201
|
!eligible.has(graphTrail.id) &&
|
|
187
|
-
|
|
202
|
+
isEligibleWorkerActivationTrail(graphTrail, options)
|
|
188
203
|
) {
|
|
189
204
|
eligible.set(graphTrail.id, graphTrail);
|
|
190
205
|
}
|
|
191
206
|
}
|
|
207
|
+
const byId = new Map(trails.map((graphTrail) => [graphTrail.id, graphTrail]));
|
|
208
|
+
const pending = [...eligible.values()];
|
|
209
|
+
for (const graphTrail of pending) {
|
|
210
|
+
const composedIds = [
|
|
211
|
+
...graphTrail.composes,
|
|
212
|
+
...Object.values(graphTrail.versions ?? {})
|
|
213
|
+
.filter(isLiveTrailVersionEntry)
|
|
214
|
+
.flatMap((entry) => entry.composes ?? []),
|
|
215
|
+
];
|
|
216
|
+
for (const reference of composedIds) {
|
|
217
|
+
const composedId =
|
|
218
|
+
typeof reference === 'string' ? reference : reference.id;
|
|
219
|
+
const composed = byId.get(composedId);
|
|
220
|
+
if (composed !== undefined && !eligible.has(composed.id)) {
|
|
221
|
+
eligible.set(composed.id, composed);
|
|
222
|
+
pending.push(composed);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
192
226
|
return [...eligible.values()];
|
|
193
227
|
};
|
|
194
228
|
|
|
195
229
|
/**
|
|
196
230
|
* All resources a trail can execute with: the current contract's declarations
|
|
197
|
-
* plus any fork version entry's own `resources`, since core runs
|
|
198
|
-
* forks with the entry's resource set.
|
|
231
|
+
* plus any live fork version entry's own `resources`, since core runs
|
|
232
|
+
* supported historical forks with the entry's resource set.
|
|
199
233
|
*/
|
|
200
234
|
const declaredTrailResources = (
|
|
201
235
|
graphTrail: Trail<unknown, unknown, unknown>
|
|
202
236
|
): readonly AnyResource[] => [
|
|
203
237
|
...graphTrail.resources,
|
|
204
|
-
...Object.values(graphTrail.versions ?? {})
|
|
205
|
-
(
|
|
206
|
-
|
|
238
|
+
...Object.values(graphTrail.versions ?? {})
|
|
239
|
+
.filter(isLiveTrailVersionEntry)
|
|
240
|
+
.flatMap((entry) => entry.resources ?? []),
|
|
207
241
|
];
|
|
208
242
|
|
|
209
243
|
const collectEnvBoundResources = (
|
|
@@ -228,8 +262,8 @@ const collectEnvBoundResources = (
|
|
|
228
262
|
|
|
229
263
|
/**
|
|
230
264
|
* Resolve every env-bound resource declared by the topo's surface-eligible
|
|
231
|
-
* trails (including fork-version resources) into a resource override map
|
|
232
|
-
* one Worker env.
|
|
265
|
+
* trails (including live fork-version resources) into a resource override map
|
|
266
|
+
* for one Worker env.
|
|
233
267
|
*
|
|
234
268
|
* Returns `Result.err` when a required binding is missing from the env or a
|
|
235
269
|
* binding value fails the resource's narrowing check. Trails filtered off the
|
|
@@ -260,7 +294,7 @@ export const buildEnvResourceOverrides = (
|
|
|
260
294
|
if (value === undefined) {
|
|
261
295
|
return Result.err(
|
|
262
296
|
new InternalError(
|
|
263
|
-
`Worker env is missing binding "${spec.binding}" required by resource "${declared.id}". Declare the binding in your wrangler configuration (for example
|
|
297
|
+
`Worker env is missing binding "${spec.binding}" required by resource "${declared.id}". Declare the binding in your wrangler configuration (for example kv_namespaces, d1_databases, r2_buckets, or queues) or provide an explicit resource override.`,
|
|
264
298
|
{ context: { binding: spec.binding, resourceId: declared.id } }
|
|
265
299
|
)
|
|
266
300
|
);
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* Service subpaths are the primary entry points:
|
|
5
5
|
* - `@ontrails/cloudflare/workers` — HTTP surface materializer (fetch handler)
|
|
6
6
|
* - `@ontrails/cloudflare/kv` — key-value resource
|
|
7
|
+
* - `@ontrails/cloudflare/d1` — D1-backed store resource
|
|
8
|
+
* - `@ontrails/cloudflare/r2` — R2 blob/object resource
|
|
9
|
+
* - `@ontrails/cloudflare/queues` — Queue producer resource and consumer
|
|
10
|
+
* materializer
|
|
7
11
|
*
|
|
8
12
|
* The root export re-exports the subpaths for convenience and adapter
|
|
9
13
|
* tooling, and owns the adapter's `trails.lock` overlay overlay
|
|
@@ -12,6 +16,17 @@
|
|
|
12
16
|
|
|
13
17
|
export { cloudflareOverlay } from './facts.js';
|
|
14
18
|
export type { CloudflareLockFacts } from './facts.js';
|
|
19
|
+
export { cloudflareD1, connectD1 } from './d1/index.js';
|
|
20
|
+
export type {
|
|
21
|
+
CloudflareD1AllResult,
|
|
22
|
+
CloudflareD1Connection,
|
|
23
|
+
CloudflareD1Database,
|
|
24
|
+
CloudflareD1Options,
|
|
25
|
+
CloudflareD1PreparedStatement,
|
|
26
|
+
CloudflareD1Resource,
|
|
27
|
+
CloudflareD1RunResult,
|
|
28
|
+
ConnectD1Options,
|
|
29
|
+
} from './d1/index.js';
|
|
15
30
|
export {
|
|
16
31
|
buildEnvResourceOverrides,
|
|
17
32
|
getEnvBinding,
|
|
@@ -32,6 +47,46 @@ export type {
|
|
|
32
47
|
CloudflareKvPutOptions,
|
|
33
48
|
CreateMemoryKvOptions,
|
|
34
49
|
} from './kv/index.js';
|
|
50
|
+
export { cloudflareR2, createMemoryR2, r2ObjectToBlobRef } from './r2/index.js';
|
|
51
|
+
export type {
|
|
52
|
+
CloudflareR2Bucket,
|
|
53
|
+
CloudflareR2Conditional,
|
|
54
|
+
CloudflareR2GetOptions,
|
|
55
|
+
CloudflareR2HttpMetadata,
|
|
56
|
+
CloudflareR2ListOptions,
|
|
57
|
+
CloudflareR2Object,
|
|
58
|
+
CloudflareR2ObjectBody,
|
|
59
|
+
CloudflareR2Objects,
|
|
60
|
+
CloudflareR2Options,
|
|
61
|
+
CloudflareR2PutBody,
|
|
62
|
+
CloudflareR2PutOptions,
|
|
63
|
+
CloudflareR2Range,
|
|
64
|
+
CloudflareR2StorageClass,
|
|
65
|
+
MemoryCloudflareR2Bucket,
|
|
66
|
+
R2ObjectToBlobRefOptions,
|
|
67
|
+
} from './r2/index.js';
|
|
68
|
+
export {
|
|
69
|
+
cloudflareQueue,
|
|
70
|
+
createMemoryQueue,
|
|
71
|
+
createQueueHandler,
|
|
72
|
+
} from './queues/index.js';
|
|
73
|
+
export type {
|
|
74
|
+
CloudflareQueue,
|
|
75
|
+
CloudflareQueueBatch,
|
|
76
|
+
CloudflareQueueHandler,
|
|
77
|
+
CloudflareQueueMessage,
|
|
78
|
+
CloudflareQueueMetrics,
|
|
79
|
+
CloudflareQueueOptions,
|
|
80
|
+
CloudflareQueueRetryOptions,
|
|
81
|
+
CloudflareQueueSendBatchOptions,
|
|
82
|
+
CloudflareQueueSendOptions,
|
|
83
|
+
CloudflareQueueSendRequest,
|
|
84
|
+
CloudflareQueueSendResult,
|
|
85
|
+
CloudflareQueuesContentType,
|
|
86
|
+
CreateQueueHandlerOptions,
|
|
87
|
+
MemoryCloudflareQueue,
|
|
88
|
+
MemoryQueueMessage,
|
|
89
|
+
} from './queues/index.js';
|
|
35
90
|
export { createWorkersHandler } from './workers/index.js';
|
|
36
91
|
export type {
|
|
37
92
|
CloudflareWorker,
|
package/src/kv/index.ts
CHANGED
|
@@ -226,7 +226,7 @@ const isKvBinding = (value: unknown): value is CloudflareKv => {
|
|
|
226
226
|
* const flags = cloudflareKv('flags', { binding: 'FLAGS' });
|
|
227
227
|
*
|
|
228
228
|
* const showFlag = trail('flag.show', {
|
|
229
|
-
*
|
|
229
|
+
* implementation: async (input, ctx) => {
|
|
230
230
|
* const value = await flags.from(ctx).get(input.key);
|
|
231
231
|
* return Result.ok({ value });
|
|
232
232
|
* },
|