@mizchi/k1c 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 +150 -0
- package/dist/canary/dispatcher-template.d.ts +17 -0
- package/dist/canary/dispatcher-template.js +42 -0
- package/dist/canary/effects-cloudflare.d.ts +9 -0
- package/dist/canary/effects-cloudflare.js +66 -0
- package/dist/canary/rollout-command.d.ts +15 -0
- package/dist/canary/rollout-command.js +92 -0
- package/dist/canary/runtime.d.ts +59 -0
- package/dist/canary/runtime.js +138 -0
- package/dist/canary/state-machine.d.ts +72 -0
- package/dist/canary/state-machine.js +161 -0
- package/dist/cli/args.d.ts +51 -0
- package/dist/cli/args.js +239 -0
- package/dist/cli/canary-integration.d.ts +11 -0
- package/dist/cli/canary-integration.js +101 -0
- package/dist/cli/format.d.ts +4 -0
- package/dist/cli/format.js +44 -0
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.js +158 -0
- package/dist/cli/run.d.ts +16 -0
- package/dist/cli/run.js +246 -0
- package/dist/manifest/lower.d.ts +22 -0
- package/dist/manifest/lower.js +913 -0
- package/dist/manifest/parse.d.ts +22 -0
- package/dist/manifest/parse.js +106 -0
- package/dist/manifest/schemas.d.ts +10359 -0
- package/dist/manifest/schemas.js +309 -0
- package/dist/manifest/types.d.ts +246 -0
- package/dist/manifest/types.js +12 -0
- package/dist/providers/configmap.d.ts +8 -0
- package/dist/providers/configmap.js +29 -0
- package/dist/providers/custom-domain.d.ts +11 -0
- package/dist/providers/custom-domain.js +120 -0
- package/dist/providers/d1-database.d.ts +9 -0
- package/dist/providers/d1-database.js +106 -0
- package/dist/providers/dispatch-namespace.d.ts +8 -0
- package/dist/providers/dispatch-namespace.js +100 -0
- package/dist/providers/dns-record.d.ts +14 -0
- package/dist/providers/dns-record.js +136 -0
- package/dist/providers/errors.d.ts +8 -0
- package/dist/providers/errors.js +64 -0
- package/dist/providers/hyperdrive.d.ts +27 -0
- package/dist/providers/hyperdrive.js +168 -0
- package/dist/providers/index.d.ts +6 -0
- package/dist/providers/index.js +36 -0
- package/dist/providers/kv-namespace.d.ts +8 -0
- package/dist/providers/kv-namespace.js +90 -0
- package/dist/providers/logpush-job.d.ts +17 -0
- package/dist/providers/logpush-job.js +181 -0
- package/dist/providers/queue.d.ts +10 -0
- package/dist/providers/queue.js +124 -0
- package/dist/providers/r2-bucket.d.ts +11 -0
- package/dist/providers/r2-bucket.js +98 -0
- package/dist/providers/registry.d.ts +9 -0
- package/dist/providers/registry.js +22 -0
- package/dist/providers/secret.d.ts +8 -0
- package/dist/providers/secret.js +30 -0
- package/dist/providers/types.d.ts +69 -0
- package/dist/providers/types.js +12 -0
- package/dist/providers/vectorize.d.ts +11 -0
- package/dist/providers/vectorize.js +110 -0
- package/dist/providers/worker.d.ts +106 -0
- package/dist/providers/worker.js +430 -0
- package/dist/providers/workflow.d.ts +10 -0
- package/dist/providers/workflow.js +103 -0
- package/dist/reconciler/apply.d.ts +10 -0
- package/dist/reconciler/apply.js +114 -0
- package/dist/reconciler/fake-provider.d.ts +48 -0
- package/dist/reconciler/fake-provider.js +83 -0
- package/dist/reconciler/plan.d.ts +6 -0
- package/dist/reconciler/plan.js +124 -0
- package/dist/reconciler/topo.d.ts +10 -0
- package/dist/reconciler/topo.js +53 -0
- package/dist/reconciler/types.d.ts +54 -0
- package/dist/reconciler/types.js +8 -0
- package/package.json +61 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { NotFound } from "./types.js";
|
|
3
|
+
import { toProviderError } from "./errors.js";
|
|
4
|
+
export const hyperdriveSchema = z.object({
|
|
5
|
+
name: z.string(),
|
|
6
|
+
origin: z.object({
|
|
7
|
+
scheme: z.enum(['postgres', 'postgresql', 'mysql']),
|
|
8
|
+
host: z.string(),
|
|
9
|
+
port: z.number().int().positive(),
|
|
10
|
+
database: z.string(),
|
|
11
|
+
user: z.string(),
|
|
12
|
+
password: z.string(),
|
|
13
|
+
}),
|
|
14
|
+
caching: z
|
|
15
|
+
.object({
|
|
16
|
+
disabled: z.boolean().optional(),
|
|
17
|
+
maxAge: z.number().int().nonnegative().optional(),
|
|
18
|
+
staleWhileRevalidate: z.number().int().nonnegative().optional(),
|
|
19
|
+
})
|
|
20
|
+
.optional(),
|
|
21
|
+
originConnectionLimit: z.number().int().positive().optional(),
|
|
22
|
+
});
|
|
23
|
+
const NAME_PREFIX = 'k1c-';
|
|
24
|
+
function parseLabel(name) {
|
|
25
|
+
if (!name.startsWith(NAME_PREFIX))
|
|
26
|
+
return null;
|
|
27
|
+
const rest = name.slice(NAME_PREFIX.length);
|
|
28
|
+
const dash = rest.indexOf('-');
|
|
29
|
+
if (dash <= 0 || dash === rest.length - 1)
|
|
30
|
+
return null;
|
|
31
|
+
return `${rest.slice(0, dash)}/${rest.slice(dash + 1)}`;
|
|
32
|
+
}
|
|
33
|
+
function buildBody(props) {
|
|
34
|
+
return {
|
|
35
|
+
name: props.name,
|
|
36
|
+
origin: {
|
|
37
|
+
scheme: props.origin.scheme,
|
|
38
|
+
host: props.origin.host,
|
|
39
|
+
port: props.origin.port,
|
|
40
|
+
database: props.origin.database,
|
|
41
|
+
user: props.origin.user,
|
|
42
|
+
password: props.origin.password,
|
|
43
|
+
},
|
|
44
|
+
...(props.caching !== undefined
|
|
45
|
+
? {
|
|
46
|
+
caching: {
|
|
47
|
+
...(props.caching.disabled !== undefined ? { disabled: props.caching.disabled } : {}),
|
|
48
|
+
...(props.caching.maxAge !== undefined ? { max_age: props.caching.maxAge } : {}),
|
|
49
|
+
...(props.caching.staleWhileRevalidate !== undefined
|
|
50
|
+
? { stale_while_revalidate: props.caching.staleWhileRevalidate }
|
|
51
|
+
: {}),
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
: {}),
|
|
55
|
+
...(props.originConnectionLimit !== undefined
|
|
56
|
+
? { origin_connection_limit: props.originConnectionLimit }
|
|
57
|
+
: {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export const hyperdriveProvider = {
|
|
61
|
+
resourceType: 'Hyperdrive',
|
|
62
|
+
schema: hyperdriveSchema,
|
|
63
|
+
async *list(ctx) {
|
|
64
|
+
let iter;
|
|
65
|
+
try {
|
|
66
|
+
iter = ctx.cloudflare.hyperdrive.configs.list({ account_id: ctx.accountId });
|
|
67
|
+
}
|
|
68
|
+
catch (raw) {
|
|
69
|
+
throw toProviderError(raw);
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
for await (const cfg of iter) {
|
|
73
|
+
const cfgName = cfg.name;
|
|
74
|
+
const cfgId = cfg.id;
|
|
75
|
+
if (!cfgName || !cfgId)
|
|
76
|
+
continue;
|
|
77
|
+
const label = parseLabel(cfgName);
|
|
78
|
+
if (label === null)
|
|
79
|
+
continue;
|
|
80
|
+
yield { nativeId: cfgId, label };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (raw) {
|
|
84
|
+
throw toProviderError(raw);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
async read(ctx, nativeId) {
|
|
88
|
+
try {
|
|
89
|
+
const cfg = await ctx.cloudflare.hyperdrive.configs.get(nativeId, {
|
|
90
|
+
account_id: ctx.accountId,
|
|
91
|
+
});
|
|
92
|
+
const c = cfg;
|
|
93
|
+
if (!c.name || !c.origin?.scheme || !c.origin?.host || c.origin?.port === undefined) {
|
|
94
|
+
return NotFound;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
name: c.name,
|
|
98
|
+
origin: {
|
|
99
|
+
scheme: c.origin.scheme,
|
|
100
|
+
host: c.origin.host,
|
|
101
|
+
port: c.origin.port,
|
|
102
|
+
database: c.origin.database ?? '',
|
|
103
|
+
user: c.origin.user ?? '',
|
|
104
|
+
// Cloudflare never returns the password; using a sentinel makes diffs honest:
|
|
105
|
+
// the caller's desired side has a real password, so propertiesEqual will
|
|
106
|
+
// disagree, and update() runs to re-upload the correct password every apply.
|
|
107
|
+
password: '<write-only>',
|
|
108
|
+
},
|
|
109
|
+
...(c.caching !== undefined
|
|
110
|
+
? {
|
|
111
|
+
caching: {
|
|
112
|
+
...(c.caching.disabled !== undefined ? { disabled: c.caching.disabled } : {}),
|
|
113
|
+
...(c.caching.max_age !== undefined ? { maxAge: c.caching.max_age } : {}),
|
|
114
|
+
...(c.caching.stale_while_revalidate !== undefined
|
|
115
|
+
? { staleWhileRevalidate: c.caching.stale_while_revalidate }
|
|
116
|
+
: {}),
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
: {}),
|
|
120
|
+
...(c.origin_connection_limit !== undefined
|
|
121
|
+
? { originConnectionLimit: c.origin_connection_limit }
|
|
122
|
+
: {}),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
catch (raw) {
|
|
126
|
+
const err = toProviderError(raw);
|
|
127
|
+
if (err.code === 'NotFound')
|
|
128
|
+
return NotFound;
|
|
129
|
+
throw err;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
async create(ctx, _label, desired) {
|
|
133
|
+
try {
|
|
134
|
+
const cfg = await ctx.cloudflare.hyperdrive.configs.create({
|
|
135
|
+
account_id: ctx.accountId,
|
|
136
|
+
...buildBody(desired),
|
|
137
|
+
});
|
|
138
|
+
const id = cfg.id ?? desired.name;
|
|
139
|
+
return { kind: 'sync', nativeId: id, properties: desired };
|
|
140
|
+
}
|
|
141
|
+
catch (raw) {
|
|
142
|
+
throw toProviderError(raw);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
async update(ctx, nativeId, _prior, desired) {
|
|
146
|
+
try {
|
|
147
|
+
const cfg = await ctx.cloudflare.hyperdrive.configs.update(nativeId, {
|
|
148
|
+
account_id: ctx.accountId,
|
|
149
|
+
...buildBody(desired),
|
|
150
|
+
});
|
|
151
|
+
const id = cfg.id ?? nativeId;
|
|
152
|
+
return { kind: 'sync', nativeId: id, properties: desired };
|
|
153
|
+
}
|
|
154
|
+
catch (raw) {
|
|
155
|
+
throw toProviderError(raw);
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
async delete(ctx, nativeId) {
|
|
159
|
+
try {
|
|
160
|
+
await ctx.cloudflare.hyperdrive.configs.delete(nativeId, { account_id: ctx.accountId });
|
|
161
|
+
return { kind: 'sync' };
|
|
162
|
+
}
|
|
163
|
+
catch (raw) {
|
|
164
|
+
throw toProviderError(raw);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
//# sourceMappingURL=hyperdrive.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ProviderRegistry } from './registry.ts';
|
|
2
|
+
export declare function createDefaultRegistry(): ProviderRegistry;
|
|
3
|
+
export { ProviderRegistry } from './registry.ts';
|
|
4
|
+
export type { CloudflareResourceProvider, ProviderContext, CreateResult, UpdateResult, DeleteResult, StatusResult, ProviderError, ProviderErrorCode, ListedResource, } from './types.ts';
|
|
5
|
+
export { NotFound, isRecoverable, RECOVERABLE_CODES } from './types.ts';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ProviderRegistry } from "./registry.js";
|
|
2
|
+
import { workerProvider } from "./worker.js";
|
|
3
|
+
import { r2BucketProvider } from "./r2-bucket.js";
|
|
4
|
+
import { kvNamespaceProvider } from "./kv-namespace.js";
|
|
5
|
+
import { configMapProvider } from "./configmap.js";
|
|
6
|
+
import { secretProvider } from "./secret.js";
|
|
7
|
+
import { dispatchNamespaceProvider } from "./dispatch-namespace.js";
|
|
8
|
+
import { customDomainProvider } from "./custom-domain.js";
|
|
9
|
+
import { hyperdriveProvider } from "./hyperdrive.js";
|
|
10
|
+
import { d1DatabaseProvider } from "./d1-database.js";
|
|
11
|
+
import { queueProvider } from "./queue.js";
|
|
12
|
+
import { vectorizeProvider } from "./vectorize.js";
|
|
13
|
+
import { dnsRecordProvider } from "./dns-record.js";
|
|
14
|
+
import { workflowProvider } from "./workflow.js";
|
|
15
|
+
import { logpushJobProvider } from "./logpush-job.js";
|
|
16
|
+
export function createDefaultRegistry() {
|
|
17
|
+
const r = new ProviderRegistry();
|
|
18
|
+
r.register(workerProvider);
|
|
19
|
+
r.register(r2BucketProvider);
|
|
20
|
+
r.register(kvNamespaceProvider);
|
|
21
|
+
r.register(configMapProvider);
|
|
22
|
+
r.register(secretProvider);
|
|
23
|
+
r.register(dispatchNamespaceProvider);
|
|
24
|
+
r.register(customDomainProvider);
|
|
25
|
+
r.register(hyperdriveProvider);
|
|
26
|
+
r.register(d1DatabaseProvider);
|
|
27
|
+
r.register(queueProvider);
|
|
28
|
+
r.register(vectorizeProvider);
|
|
29
|
+
r.register(dnsRecordProvider);
|
|
30
|
+
r.register(workflowProvider);
|
|
31
|
+
r.register(logpushJobProvider);
|
|
32
|
+
return r;
|
|
33
|
+
}
|
|
34
|
+
export { ProviderRegistry } from "./registry.js";
|
|
35
|
+
export { NotFound, isRecoverable, RECOVERABLE_CODES } from "./types.js";
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { CloudflareResourceProvider } from './types.ts';
|
|
3
|
+
export interface KVNamespaceProperties {
|
|
4
|
+
readonly title: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const kvNamespaceSchema: z.ZodType<KVNamespaceProperties>;
|
|
7
|
+
export declare const kvNamespaceProvider: CloudflareResourceProvider<KVNamespaceProperties>;
|
|
8
|
+
//# sourceMappingURL=kv-namespace.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { NotFound } from "./types.js";
|
|
3
|
+
import { toProviderError } from "./errors.js";
|
|
4
|
+
export const kvNamespaceSchema = z.object({
|
|
5
|
+
title: z.string(),
|
|
6
|
+
});
|
|
7
|
+
const TITLE_PREFIX = 'k1c/';
|
|
8
|
+
function parseLabel(title) {
|
|
9
|
+
if (!title.startsWith(TITLE_PREFIX))
|
|
10
|
+
return null;
|
|
11
|
+
const rest = title.slice(TITLE_PREFIX.length);
|
|
12
|
+
const slash = rest.indexOf('/');
|
|
13
|
+
if (slash <= 0 || slash === rest.length - 1)
|
|
14
|
+
return null;
|
|
15
|
+
const namespace = rest.slice(0, slash);
|
|
16
|
+
const name = rest.slice(slash + 1);
|
|
17
|
+
return `${namespace}/${name}`;
|
|
18
|
+
}
|
|
19
|
+
export const kvNamespaceProvider = {
|
|
20
|
+
resourceType: 'KVNamespace',
|
|
21
|
+
schema: kvNamespaceSchema,
|
|
22
|
+
async *list(ctx) {
|
|
23
|
+
let iter;
|
|
24
|
+
try {
|
|
25
|
+
iter = ctx.cloudflare.kv.namespaces.list({ account_id: ctx.accountId });
|
|
26
|
+
}
|
|
27
|
+
catch (raw) {
|
|
28
|
+
throw toProviderError(raw);
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
for await (const ns of iter) {
|
|
32
|
+
const label = parseLabel(ns.title);
|
|
33
|
+
if (label === null)
|
|
34
|
+
continue;
|
|
35
|
+
yield { nativeId: ns.id, label };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (raw) {
|
|
39
|
+
throw toProviderError(raw);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
async read(ctx, nativeId) {
|
|
43
|
+
try {
|
|
44
|
+
const ns = await ctx.cloudflare.kv.namespaces.get(nativeId, { account_id: ctx.accountId });
|
|
45
|
+
return { title: ns.title };
|
|
46
|
+
}
|
|
47
|
+
catch (raw) {
|
|
48
|
+
const err = toProviderError(raw);
|
|
49
|
+
if (err.code === 'NotFound')
|
|
50
|
+
return NotFound;
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
async create(ctx, _label, desired) {
|
|
55
|
+
try {
|
|
56
|
+
const ns = await ctx.cloudflare.kv.namespaces.create({
|
|
57
|
+
account_id: ctx.accountId,
|
|
58
|
+
title: desired.title,
|
|
59
|
+
});
|
|
60
|
+
return { kind: 'sync', nativeId: ns.id, properties: { title: ns.title } };
|
|
61
|
+
}
|
|
62
|
+
catch (raw) {
|
|
63
|
+
throw toProviderError(raw);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
async update(ctx, nativeId, prior, desired) {
|
|
67
|
+
if (prior.title === desired.title)
|
|
68
|
+
return { kind: 'noop' };
|
|
69
|
+
try {
|
|
70
|
+
const ns = await ctx.cloudflare.kv.namespaces.update(nativeId, {
|
|
71
|
+
account_id: ctx.accountId,
|
|
72
|
+
title: desired.title,
|
|
73
|
+
});
|
|
74
|
+
return { kind: 'sync', nativeId: ns.id, properties: { title: ns.title } };
|
|
75
|
+
}
|
|
76
|
+
catch (raw) {
|
|
77
|
+
throw toProviderError(raw);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
async delete(ctx, nativeId) {
|
|
81
|
+
try {
|
|
82
|
+
await ctx.cloudflare.kv.namespaces.delete(nativeId, { account_id: ctx.accountId });
|
|
83
|
+
return { kind: 'sync' };
|
|
84
|
+
}
|
|
85
|
+
catch (raw) {
|
|
86
|
+
throw toProviderError(raw);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=kv-namespace.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { CloudflareResourceProvider } from './types.ts';
|
|
3
|
+
export interface LogpushJobProperties {
|
|
4
|
+
readonly jobName: string;
|
|
5
|
+
readonly scope: {
|
|
6
|
+
readonly zoneId: string;
|
|
7
|
+
} | {
|
|
8
|
+
readonly accountId: string;
|
|
9
|
+
};
|
|
10
|
+
readonly dataset: string;
|
|
11
|
+
readonly destinationConf: string;
|
|
12
|
+
readonly enabled?: boolean;
|
|
13
|
+
readonly filter?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const logpushJobPropsSchema: z.ZodType<LogpushJobProperties>;
|
|
16
|
+
export declare const logpushJobProvider: CloudflareResourceProvider<LogpushJobProperties>;
|
|
17
|
+
//# sourceMappingURL=logpush-job.d.ts.map
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { NotFound } from "./types.js";
|
|
3
|
+
import { toProviderError } from "./errors.js";
|
|
4
|
+
export const logpushJobPropsSchema = z.object({
|
|
5
|
+
jobName: z.string(),
|
|
6
|
+
scope: z.union([
|
|
7
|
+
z.object({ zoneId: z.string() }),
|
|
8
|
+
z.object({ accountId: z.string() }),
|
|
9
|
+
]),
|
|
10
|
+
dataset: z.string(),
|
|
11
|
+
destinationConf: z.string(),
|
|
12
|
+
enabled: z.boolean().optional(),
|
|
13
|
+
filter: z.string().optional(),
|
|
14
|
+
});
|
|
15
|
+
const NAME_PREFIX = 'k1c-';
|
|
16
|
+
function parseLabel(name) {
|
|
17
|
+
if (!name.startsWith(NAME_PREFIX))
|
|
18
|
+
return null;
|
|
19
|
+
const rest = name.slice(NAME_PREFIX.length);
|
|
20
|
+
const dash = rest.indexOf('-');
|
|
21
|
+
if (dash <= 0 || dash === rest.length - 1)
|
|
22
|
+
return null;
|
|
23
|
+
return `${rest.slice(0, dash)}/${rest.slice(dash + 1)}`;
|
|
24
|
+
}
|
|
25
|
+
function scopeParams(scope) {
|
|
26
|
+
return 'zoneId' in scope
|
|
27
|
+
? { zone_id: scope.zoneId }
|
|
28
|
+
: { account_id: scope.accountId };
|
|
29
|
+
}
|
|
30
|
+
export const logpushJobProvider = {
|
|
31
|
+
resourceType: 'LogpushJob',
|
|
32
|
+
schema: logpushJobPropsSchema,
|
|
33
|
+
async *list(ctx) {
|
|
34
|
+
// List by zone (if ctx has a zoneId) and / or by account.
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
const params = [
|
|
37
|
+
{ account_id: ctx.accountId },
|
|
38
|
+
];
|
|
39
|
+
if (ctx.zoneId !== undefined)
|
|
40
|
+
params.push({ zone_id: ctx.zoneId });
|
|
41
|
+
for (const p of params) {
|
|
42
|
+
let iter;
|
|
43
|
+
try {
|
|
44
|
+
iter = ctx.cloudflare.logpush.jobs.list(p);
|
|
45
|
+
}
|
|
46
|
+
catch (raw) {
|
|
47
|
+
throw toProviderError(raw);
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
for await (const job of iter) {
|
|
51
|
+
if (job === null)
|
|
52
|
+
continue;
|
|
53
|
+
const j = job;
|
|
54
|
+
if (j.id === undefined || seen.has(j.id))
|
|
55
|
+
continue;
|
|
56
|
+
seen.add(j.id);
|
|
57
|
+
if (!j.name)
|
|
58
|
+
continue;
|
|
59
|
+
const label = parseLabel(j.name);
|
|
60
|
+
if (label === null)
|
|
61
|
+
continue;
|
|
62
|
+
yield { nativeId: String(j.id), label };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (raw) {
|
|
66
|
+
throw toProviderError(raw);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
async read(ctx, nativeId) {
|
|
71
|
+
const id = Number(nativeId);
|
|
72
|
+
if (Number.isNaN(id))
|
|
73
|
+
return NotFound;
|
|
74
|
+
// Try account scope first; fall back to zone scope if ctx has one. Logpush jobs
|
|
75
|
+
// are addressable by id under the scope they were created in, so we probe both.
|
|
76
|
+
const scopes = [
|
|
77
|
+
{ account_id: ctx.accountId },
|
|
78
|
+
];
|
|
79
|
+
if (ctx.zoneId !== undefined)
|
|
80
|
+
scopes.push({ zone_id: ctx.zoneId });
|
|
81
|
+
for (const scope of scopes) {
|
|
82
|
+
try {
|
|
83
|
+
const job = await ctx.cloudflare.logpush.jobs.get(id, scope);
|
|
84
|
+
if (job === null)
|
|
85
|
+
continue;
|
|
86
|
+
const j = job;
|
|
87
|
+
if (!j.name || !j.dataset || !j.destination_conf)
|
|
88
|
+
continue;
|
|
89
|
+
const propsScope = scope.zone_id !== undefined
|
|
90
|
+
? { zoneId: scope.zone_id }
|
|
91
|
+
: { accountId: scope.account_id };
|
|
92
|
+
return {
|
|
93
|
+
jobName: j.name,
|
|
94
|
+
scope: propsScope,
|
|
95
|
+
dataset: j.dataset,
|
|
96
|
+
destinationConf: j.destination_conf,
|
|
97
|
+
...(j.enabled !== undefined ? { enabled: j.enabled } : {}),
|
|
98
|
+
...(j.filter !== undefined ? { filter: j.filter } : {}),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (raw) {
|
|
102
|
+
const err = toProviderError(raw);
|
|
103
|
+
if (err.code === 'NotFound')
|
|
104
|
+
continue;
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return NotFound;
|
|
109
|
+
},
|
|
110
|
+
async create(ctx, _label, desired) {
|
|
111
|
+
try {
|
|
112
|
+
const job = await ctx.cloudflare.logpush.jobs.create({
|
|
113
|
+
...scopeParams(desired.scope),
|
|
114
|
+
name: desired.jobName,
|
|
115
|
+
dataset: desired.dataset,
|
|
116
|
+
destination_conf: desired.destinationConf,
|
|
117
|
+
...(desired.enabled !== undefined ? { enabled: desired.enabled } : {}),
|
|
118
|
+
...(desired.filter !== undefined ? { filter: desired.filter } : {}),
|
|
119
|
+
});
|
|
120
|
+
const id = job?.id;
|
|
121
|
+
if (id === undefined)
|
|
122
|
+
throw new Error('logpush.jobs.create returned no id');
|
|
123
|
+
return { kind: 'sync', nativeId: String(id), properties: desired };
|
|
124
|
+
}
|
|
125
|
+
catch (raw) {
|
|
126
|
+
throw toProviderError(raw);
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
async update(ctx, nativeId, _prior, desired) {
|
|
130
|
+
const id = Number(nativeId);
|
|
131
|
+
if (Number.isNaN(id)) {
|
|
132
|
+
throw {
|
|
133
|
+
code: 'InvalidRequest',
|
|
134
|
+
recoverable: false,
|
|
135
|
+
message: `logpushJob.update: nativeId "${nativeId}" is not a numeric job id`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
await ctx.cloudflare.logpush.jobs.update(id, {
|
|
140
|
+
...scopeParams(desired.scope),
|
|
141
|
+
destination_conf: desired.destinationConf,
|
|
142
|
+
...(desired.enabled !== undefined ? { enabled: desired.enabled } : {}),
|
|
143
|
+
...(desired.filter !== undefined ? { filter: desired.filter } : {}),
|
|
144
|
+
});
|
|
145
|
+
return { kind: 'sync', nativeId, properties: desired };
|
|
146
|
+
}
|
|
147
|
+
catch (raw) {
|
|
148
|
+
throw toProviderError(raw);
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
async delete(ctx, nativeId) {
|
|
152
|
+
const id = Number(nativeId);
|
|
153
|
+
if (Number.isNaN(id)) {
|
|
154
|
+
throw {
|
|
155
|
+
code: 'InvalidRequest',
|
|
156
|
+
recoverable: false,
|
|
157
|
+
message: `logpushJob.delete: nativeId "${nativeId}" is not a numeric job id`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const scopes = [
|
|
161
|
+
{ account_id: ctx.accountId },
|
|
162
|
+
];
|
|
163
|
+
if (ctx.zoneId !== undefined)
|
|
164
|
+
scopes.push({ zone_id: ctx.zoneId });
|
|
165
|
+
let lastErr;
|
|
166
|
+
for (const scope of scopes) {
|
|
167
|
+
try {
|
|
168
|
+
await ctx.cloudflare.logpush.jobs.delete(id, scope);
|
|
169
|
+
return { kind: 'sync' };
|
|
170
|
+
}
|
|
171
|
+
catch (raw) {
|
|
172
|
+
const err = toProviderError(raw);
|
|
173
|
+
if (err.code !== 'NotFound')
|
|
174
|
+
throw err;
|
|
175
|
+
lastErr = raw;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
throw toProviderError(lastErr);
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
//# sourceMappingURL=logpush-job.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { CloudflareResourceProvider } from './types.ts';
|
|
3
|
+
export interface QueueProperties {
|
|
4
|
+
readonly queueName: string;
|
|
5
|
+
/** When set, k1c will register the named Worker as a consumer of this queue. */
|
|
6
|
+
readonly consumerWorkerName?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const queuePropsSchema: z.ZodType<QueueProperties>;
|
|
9
|
+
export declare const queueProvider: CloudflareResourceProvider<QueueProperties>;
|
|
10
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { NotFound } from "./types.js";
|
|
3
|
+
import { toProviderError } from "./errors.js";
|
|
4
|
+
export const queuePropsSchema = z.object({
|
|
5
|
+
queueName: z.string(),
|
|
6
|
+
consumerWorkerName: z.string().optional(),
|
|
7
|
+
});
|
|
8
|
+
const NAME_PREFIX = 'k1c-';
|
|
9
|
+
function parseLabel(name) {
|
|
10
|
+
if (!name.startsWith(NAME_PREFIX))
|
|
11
|
+
return null;
|
|
12
|
+
const rest = name.slice(NAME_PREFIX.length);
|
|
13
|
+
const dash = rest.indexOf('-');
|
|
14
|
+
if (dash <= 0 || dash === rest.length - 1)
|
|
15
|
+
return null;
|
|
16
|
+
return `${rest.slice(0, dash)}/${rest.slice(dash + 1)}`;
|
|
17
|
+
}
|
|
18
|
+
export const queueProvider = {
|
|
19
|
+
resourceType: 'Queue',
|
|
20
|
+
schema: queuePropsSchema,
|
|
21
|
+
async *list(ctx) {
|
|
22
|
+
let iter;
|
|
23
|
+
try {
|
|
24
|
+
iter = ctx.cloudflare.queues.list({ account_id: ctx.accountId });
|
|
25
|
+
}
|
|
26
|
+
catch (raw) {
|
|
27
|
+
throw toProviderError(raw);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
for await (const q of iter) {
|
|
31
|
+
const qName = q.queue_name;
|
|
32
|
+
const qId = q.queue_id;
|
|
33
|
+
if (!qName || !qId)
|
|
34
|
+
continue;
|
|
35
|
+
const label = parseLabel(qName);
|
|
36
|
+
if (label === null)
|
|
37
|
+
continue;
|
|
38
|
+
yield { nativeId: qId, label };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (raw) {
|
|
42
|
+
throw toProviderError(raw);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
async read(ctx, nativeId) {
|
|
46
|
+
try {
|
|
47
|
+
const q = await ctx.cloudflare.queues.get(nativeId, { account_id: ctx.accountId });
|
|
48
|
+
const obj = q;
|
|
49
|
+
if (!obj.queue_name)
|
|
50
|
+
return NotFound;
|
|
51
|
+
// Pick the first Worker-style consumer if any. Multi-consumer queues are out of
|
|
52
|
+
// scope for v0.2; the reconciler will overwrite with the manifest's intent.
|
|
53
|
+
const consumer = (obj.consumers ?? []).find((c) => typeof (c.script ?? c.service) === 'string');
|
|
54
|
+
const consumerWorkerName = consumer?.script ?? consumer?.service;
|
|
55
|
+
return {
|
|
56
|
+
queueName: obj.queue_name,
|
|
57
|
+
...(consumerWorkerName !== undefined ? { consumerWorkerName } : {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (raw) {
|
|
61
|
+
const err = toProviderError(raw);
|
|
62
|
+
if (err.code === 'NotFound')
|
|
63
|
+
return NotFound;
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
async create(ctx, _label, desired) {
|
|
68
|
+
try {
|
|
69
|
+
const q = await ctx.cloudflare.queues.create({
|
|
70
|
+
account_id: ctx.accountId,
|
|
71
|
+
queue_name: desired.queueName,
|
|
72
|
+
});
|
|
73
|
+
const id = q.queue_id ?? desired.queueName;
|
|
74
|
+
if (desired.consumerWorkerName !== undefined) {
|
|
75
|
+
await registerConsumer(ctx, id, desired.consumerWorkerName);
|
|
76
|
+
}
|
|
77
|
+
return { kind: 'sync', nativeId: id, properties: desired };
|
|
78
|
+
}
|
|
79
|
+
catch (raw) {
|
|
80
|
+
throw toProviderError(raw);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
async update(ctx, nativeId, prior, desired) {
|
|
84
|
+
if (prior.queueName !== desired.queueName) {
|
|
85
|
+
throw {
|
|
86
|
+
code: 'NotUpdatable',
|
|
87
|
+
recoverable: false,
|
|
88
|
+
suggest: 'recreate',
|
|
89
|
+
message: 'Queue name is immutable; recreate to change.',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (prior.consumerWorkerName !== desired.consumerWorkerName) {
|
|
93
|
+
try {
|
|
94
|
+
// Cloudflare's queue consumer API supports multiple consumers; we treat the
|
|
95
|
+
// manifest as authoritative and re-register. A more careful diff would
|
|
96
|
+
// delete-then-create, but for v0.2 the upsert pattern is good enough.
|
|
97
|
+
if (desired.consumerWorkerName !== undefined) {
|
|
98
|
+
await registerConsumer(ctx, nativeId, desired.consumerWorkerName);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (raw) {
|
|
102
|
+
throw toProviderError(raw);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { kind: 'sync', nativeId, properties: desired };
|
|
106
|
+
},
|
|
107
|
+
async delete(ctx, nativeId) {
|
|
108
|
+
try {
|
|
109
|
+
await ctx.cloudflare.queues.delete(nativeId, { account_id: ctx.accountId });
|
|
110
|
+
return { kind: 'sync' };
|
|
111
|
+
}
|
|
112
|
+
catch (raw) {
|
|
113
|
+
throw toProviderError(raw);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
async function registerConsumer(ctx, queueId, workerName) {
|
|
118
|
+
await ctx.cloudflare.queues.consumers.create(queueId, {
|
|
119
|
+
account_id: ctx.accountId,
|
|
120
|
+
type: 'worker',
|
|
121
|
+
script_name: workerName,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { CloudflareResourceProvider } from './types.ts';
|
|
3
|
+
export type R2Location = 'wnam' | 'enam' | 'weur' | 'eeur' | 'apac' | 'oc';
|
|
4
|
+
export interface R2BucketProperties {
|
|
5
|
+
readonly bucketName: string;
|
|
6
|
+
readonly location?: R2Location;
|
|
7
|
+
readonly storageClass?: 'Standard' | 'InfrequentAccess';
|
|
8
|
+
}
|
|
9
|
+
export declare const r2BucketSchema: z.ZodType<R2BucketProperties>;
|
|
10
|
+
export declare const r2BucketProvider: CloudflareResourceProvider<R2BucketProperties>;
|
|
11
|
+
//# sourceMappingURL=r2-bucket.d.ts.map
|