@pellux/goodvibes-sdk 0.25.17 → 0.25.19

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.
@@ -3,7 +3,7 @@
3
3
  "product": {
4
4
  "id": "goodvibes",
5
5
  "surface": "operator",
6
- "version": "0.25.17"
6
+ "version": "0.25.19"
7
7
  },
8
8
  "auth": {
9
9
  "modes": [
@@ -1,6 +1,6 @@
1
1
  export declare const FOUNDATION_METADATA: {
2
2
  readonly productId: "goodvibes";
3
- readonly productVersion: "0.25.17";
3
+ readonly productVersion: "0.25.19";
4
4
  readonly operatorMethodCount: 224;
5
5
  readonly operatorEventCount: 30;
6
6
  readonly peerEndpointCount: 6;
@@ -1,7 +1,7 @@
1
1
  // Synced from packages/contracts/src/generated/foundation-metadata.ts
2
2
  export const FOUNDATION_METADATA = {
3
3
  "productId": "goodvibes",
4
- "productVersion": "0.25.17",
4
+ "productVersion": "0.25.19",
5
5
  "operatorMethodCount": 224,
6
6
  "operatorEventCount": 30,
7
7
  "peerEndpointCount": 6
@@ -3,7 +3,7 @@ export const OPERATOR_CONTRACT = {
3
3
  "product": {
4
4
  "id": "goodvibes",
5
5
  "surface": "operator",
6
- "version": "0.25.17"
6
+ "version": "0.25.19"
7
7
  },
8
8
  "auth": {
9
9
  "modes": [
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/cloudflare/manager.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAIV,6BAA6B,EAC7B,4BAA4B,EAC5B,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EAGvB,+BAA+B,EAC/B,gCAAgC,EAChC,wBAAwB,EACxB,yBAAyB,EAMzB,gCAAgC,EAChC,iCAAiC,EAEjC,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAkBpB,qBAAa,6BAA6B;IAI5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqD;IAClF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAEZ,OAAO,EAAE,6BAA6B;IAK7D,cAAc,IAAI,OAAO,CAAC,4BAA4B,CAAC;IA0C7D,iBAAiB,CAAC,KAAK,GAAE,gCAAqC,GAAG,iCAAiC;IAkB5F,sBAAsB,CAAC,KAAK,EAAE,+BAA+B,GAAG,OAAO,CAAC,gCAAgC,CAAC;IAqEzG,QAAQ,CAAC,KAAK,GAAE,uBAA4B,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAuEhF,QAAQ,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAuB3E,SAAS,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IA0S9E,MAAM,CAAC,KAAK,GAAE,qBAA0B,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAe1E,OAAO,CAAC,KAAK,GAAE,sBAA2B,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA0BnF,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,iBAAiB;YAYX,eAAe;YAaf,oBAAoB;YAapB,wBAAwB;YAaxB,gBAAgB;YAahB,WAAW;IAOzB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,yBAAyB;YAQnB,WAAW;IAazB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,SAAS;CAMlB"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/cloudflare/manager.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAIV,6BAA6B,EAC7B,4BAA4B,EAC5B,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EAGvB,+BAA+B,EAC/B,gCAAgC,EAChC,wBAAwB,EACxB,yBAAyB,EAMzB,gCAAgC,EAChC,iCAAiC,EAEjC,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAyBpB,qBAAa,6BAA6B;IAI5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqD;IAClF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAEZ,OAAO,EAAE,6BAA6B;IAK7D,cAAc,IAAI,OAAO,CAAC,4BAA4B,CAAC;IA0C7D,iBAAiB,CAAC,KAAK,GAAE,gCAAqC,GAAG,iCAAiC;IAkB5F,sBAAsB,CAAC,KAAK,EAAE,+BAA+B,GAAG,OAAO,CAAC,gCAAgC,CAAC;IAqEzG,QAAQ,CAAC,KAAK,GAAE,uBAA4B,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAuEhF,QAAQ,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAuB3E,SAAS,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IA0S9E,MAAM,CAAC,KAAK,GAAE,qBAA0B,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAe1E,OAAO,CAAC,KAAK,GAAE,sBAA2B,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAwBnF,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,iBAAiB;YAYX,eAAe;YAaf,oBAAoB;YAapB,wBAAwB;YAaxB,gBAAgB;YAahB,WAAW;IAOzB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,yBAAyB;YAQnB,WAAW;IAazB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,SAAS;CAMlB"}
@@ -4,9 +4,10 @@ import { createCloudflareApiClient } from './client.js';
4
4
  import { readCloudflareConfig } from './config.js';
5
5
  import { CLOUDFLARE_API_TOKEN_KEY, CLOUDFLARE_WORKER_CLIENT_TOKEN_KEY, CLOUDFLARE_WORKER_OPERATOR_TOKEN_KEY, DEFAULT_DLQ_NAME, DEFAULT_DO_NAMESPACE_NAME, DEFAULT_KV_NAMESPACE_NAME, DEFAULT_QUEUE_NAME, DEFAULT_R2_BUCKET_NAME, DEFAULT_SECRETS_STORE_NAME, DEFAULT_TUNNEL_NAME, DEFAULT_WORKER_CRON, DEFAULT_WORKER_NAME, } from './constants.js';
6
6
  import { discoverZones, resolveZone, selectDiscoveredZone, tryDiscover, } from './discovery.js';
7
- import { configureDns, configureWorkerSubdomain, ensureAccess, ensureKvNamespace, ensureQueue, ensureQueueConsumer, ensureR2Bucket, ensureSecretsStore, ensureTunnel, findDurableObjectNamespace, uploadWorker, } from './resources.js';
7
+ import { configureDns, ensureAccess, ensureKvNamespace, ensureQueue, ensureQueueConsumer, ensureR2Bucket, ensureSecretsStore, ensureTunnel, findDurableObjectNamespace, } from './resources.js';
8
8
  import { CloudflareControlPlaneError } from './types.js';
9
9
  import { buildTokenPolicies, buildTokenRequirements, clean, collectAsync, collectSingleAccount, hostnameFromUrl, requireKvNamespaceId, requireQueueId, resolveComponents, resolvePermissionGroups, safeResponseText, stripTrailingSlash, verifyCreatedTokenPolicies, } from './utils.js';
10
+ import { configureWorkerSchedule, configureWorkerSubdomain, disableWorkerSchedule, disableWorkerSubdomain, uploadWorker, } from './worker-settings.js';
10
11
  export class CloudflareControlPlaneManager {
11
12
  options;
12
13
  createClient;
@@ -285,9 +286,13 @@ export class CloudflareControlPlaneManager {
285
286
  deadLetterQueueId = requireQueueId(deadLetterQueue, deadLetterQueueName);
286
287
  queueId = requireQueueId(queue, queueName);
287
288
  }
288
- const kv = components.kv ? await ensureKvNamespace(resourceContext, client, accountId, clean(input.kvNamespaceName) || config.kvNamespaceName || DEFAULT_KV_NAMESPACE_NAME, persist, steps) : undefined;
289
+ const kvName = clean(input.kvNamespaceName) || config.kvNamespaceName || DEFAULT_KV_NAMESPACE_NAME;
290
+ const kvId = clean(input.kvNamespaceId) || config.kvNamespaceId;
291
+ const kv = components.kv ? await ensureKvNamespace(resourceContext, client, accountId, kvName, kvId, persist, steps) : undefined;
289
292
  const r2 = components.r2 ? await ensureR2Bucket(resourceContext, client, accountId, clean(input.r2BucketName) || config.r2BucketName || DEFAULT_R2_BUCKET_NAME, persist, steps) : undefined;
290
- const secretsStore = components.secretsStore ? await ensureSecretsStore(resourceContext, client, accountId, clean(input.secretsStoreName) || config.secretsStoreName || DEFAULT_SECRETS_STORE_NAME, persist, steps) : undefined;
293
+ const secretsStoreName = clean(input.secretsStoreName) || config.secretsStoreName || DEFAULT_SECRETS_STORE_NAME;
294
+ const secretsStoreId = clean(input.secretsStoreId) || config.secretsStoreId;
295
+ const secretsStore = components.secretsStore ? await ensureSecretsStore(resourceContext, client, accountId, secretsStoreName, secretsStoreId, persist, steps) : undefined;
291
296
  const tunnel = components.zeroTrustTunnel
292
297
  ? await ensureTunnel(resourceContext, client, {
293
298
  accountId,
@@ -374,11 +379,7 @@ export class CloudflareControlPlaneManager {
374
379
  });
375
380
  }
376
381
  if (workerCron) {
377
- await client.workers.scripts.schedules.update(workerName, {
378
- account_id: accountId,
379
- body: [{ cron: workerCron }],
380
- });
381
- steps.push({ name: 'configure-cron', status: 'ok', message: `Configured Worker cron ${workerCron}.` });
382
+ await configureWorkerSchedule(client, { accountId, workerName, workerCron, steps });
382
383
  }
383
384
  else {
384
385
  steps.push({ name: 'configure-cron', status: 'skipped', message: 'No Worker cron configured.' });
@@ -524,12 +525,10 @@ export class CloudflareControlPlaneManager {
524
525
  if (apiToken.value && accountId) {
525
526
  const client = await this.createClient(apiToken.value);
526
527
  if (input.disableCron !== false) {
527
- await client.workers.scripts.schedules.update(workerName, { account_id: accountId, body: [] });
528
- steps.push({ name: 'disable-cron', status: 'ok', message: `Removed Worker cron schedules from ${workerName}.` });
528
+ await disableWorkerSchedule(client, accountId, workerName, steps);
529
529
  }
530
530
  if (input.disableWorkerSubdomain) {
531
- await client.workers.scripts.subdomain.delete(workerName, { account_id: accountId });
532
- steps.push({ name: 'disable-worker-subdomain', status: 'ok', message: `Disabled workers.dev route for ${workerName}.` });
531
+ await disableWorkerSubdomain(client, accountId, workerName, steps);
533
532
  }
534
533
  }
535
534
  else {
@@ -6,9 +6,9 @@ export interface CloudflareProvisioningContext {
6
6
  readonly storeSecret: (key: string, value: string) => Promise<void>;
7
7
  }
8
8
  export declare function ensureQueue(client: CloudflareApiClient, accountId: string, queueName: string, steps: CloudflareProvisionStep[], stepName: string): Promise<CloudflareQueueLike>;
9
- export declare function ensureKvNamespace(context: CloudflareProvisioningContext, client: CloudflareApiClient, accountId: string, namespaceName: string, persist: boolean, steps: CloudflareProvisionStep[]): Promise<CloudflareKvNamespaceLike>;
9
+ export declare function ensureKvNamespace(context: CloudflareProvisioningContext, client: CloudflareApiClient, accountId: string, namespaceName: string, configuredNamespaceId: string, persist: boolean, steps: CloudflareProvisionStep[]): Promise<CloudflareKvNamespaceLike>;
10
10
  export declare function ensureR2Bucket(context: CloudflareProvisioningContext, client: CloudflareApiClient, accountId: string, bucketName: string, persist: boolean, steps: CloudflareProvisionStep[]): Promise<CloudflareR2BucketLike>;
11
- export declare function ensureSecretsStore(context: CloudflareProvisioningContext, client: CloudflareApiClient, accountId: string, storeName: string, persist: boolean, steps: CloudflareProvisionStep[]): Promise<CloudflareSecretsStoreLike>;
11
+ export declare function ensureSecretsStore(context: CloudflareProvisioningContext, client: CloudflareApiClient, accountId: string, storeName: string, configuredStoreId: string, persist: boolean, steps: CloudflareProvisionStep[]): Promise<CloudflareSecretsStoreLike>;
12
12
  export declare function ensureTunnel(context: CloudflareProvisioningContext, client: CloudflareApiClient, input: {
13
13
  readonly accountId: string;
14
14
  readonly tunnelName: string;
@@ -50,24 +50,6 @@ export declare function configureDns(client: CloudflareApiClient, input: {
50
50
  readonly steps: CloudflareProvisionStep[];
51
51
  }): Promise<readonly CloudflareDnsRecordLike[]>;
52
52
  export declare function findDurableObjectNamespace(context: CloudflareProvisioningContext, client: CloudflareApiClient, accountId: string, namespaceName: string, persist: boolean, steps: CloudflareProvisionStep[]): Promise<CloudflareDurableObjectNamespaceLike | undefined>;
53
- export declare function uploadWorker(client: CloudflareApiClient, input: {
54
- readonly accountId: string;
55
- readonly workerName: string;
56
- readonly queueName: string;
57
- readonly daemonBaseUrl: string;
58
- readonly queueJobPayloads: boolean;
59
- readonly kvNamespaceId: string;
60
- readonly r2BucketName: string;
61
- readonly durableObject: boolean;
62
- }): Promise<void>;
63
- export declare function configureWorkerSubdomain(context: CloudflareProvisioningContext, client: CloudflareApiClient, input: {
64
- readonly accountId: string;
65
- readonly workerName: string;
66
- readonly requestedSubdomain?: string;
67
- readonly enableWorkersDev: boolean;
68
- readonly steps: CloudflareProvisionStep[];
69
- readonly persist: boolean;
70
- }): Promise<string>;
71
53
  export declare function ensureQueueConsumer(client: CloudflareApiClient, input: {
72
54
  readonly accountId: string;
73
55
  readonly queueId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/cloudflare/resources.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/cloudflare/resources.ts"],"names":[],"mappings":"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"}
@@ -1,71 +1,116 @@
1
1
  import { summarizeError } from '../utils/error-display.js';
2
- import { CLOUDFLARE_ACCESS_SERVICE_TOKEN_KEY, CLOUDFLARE_TUNNEL_TOKEN_KEY, DEFAULT_DO_NAMESPACE_NAME, } from './constants.js';
2
+ import { CLOUDFLARE_ACCESS_SERVICE_TOKEN_KEY, CLOUDFLARE_TUNNEL_TOKEN_KEY, } from './constants.js';
3
3
  import { CloudflareControlPlaneError } from './types.js';
4
4
  import { clean, collectAsync, hostnameFromUrl } from './utils.js';
5
- import { GOODVIBES_CLOUDFLARE_WORKER_MODULE } from './worker-source.js';
6
5
  export async function ensureQueue(client, accountId, queueName, steps, stepName) {
7
- for await (const queue of client.queues.list({ account_id: accountId })) {
8
- if (queue.queue_name === queueName) {
9
- steps.push({ name: stepName, status: 'ok', message: `Using existing Cloudflare Queue ${queueName}.`, resourceId: queue.queue_id });
10
- return queue;
6
+ const existing = await findQueueByName(client, accountId, queueName);
7
+ if (existing) {
8
+ steps.push({ name: stepName, status: 'ok', message: `Using existing Cloudflare Queue ${queueName}.`, resourceId: existing.queue_id });
9
+ return existing;
10
+ }
11
+ try {
12
+ const created = await client.queues.create({ account_id: accountId, queue_name: queueName });
13
+ steps.push({ name: stepName, status: 'ok', message: `Created Cloudflare Queue ${queueName}.`, resourceId: created.queue_id });
14
+ return created;
15
+ }
16
+ catch (error) {
17
+ const recovered = await findQueueByName(client, accountId, queueName);
18
+ if (recovered) {
19
+ steps.push({ name: stepName, status: 'ok', message: `Using existing Cloudflare Queue ${queueName} after create retry: ${summarizeError(error)}`, resourceId: recovered.queue_id });
20
+ return recovered;
11
21
  }
22
+ throw error;
12
23
  }
13
- const created = await client.queues.create({ account_id: accountId, queue_name: queueName });
14
- steps.push({ name: stepName, status: 'ok', message: `Created Cloudflare Queue ${queueName}.`, resourceId: created.queue_id });
15
- return created;
16
24
  }
17
- export async function ensureKvNamespace(context, client, accountId, namespaceName, persist, steps) {
25
+ export async function ensureKvNamespace(context, client, accountId, namespaceName, configuredNamespaceId, persist, steps) {
18
26
  if (!client.kv) {
19
27
  throw new CloudflareControlPlaneError('The Cloudflare client does not expose KV namespace APIs.', 'CLOUDFLARE_KV_API_UNAVAILABLE', 500);
20
28
  }
21
- for await (const namespace of client.kv.namespaces.list({ account_id: accountId })) {
22
- if (namespace.title === namespaceName) {
23
- context.setConfig('cloudflare.kvNamespaceName', namespaceName, persist);
24
- if (namespace.id)
25
- context.setConfig('cloudflare.kvNamespaceId', namespace.id, persist);
26
- steps.push({ name: 'kv-namespace', status: 'ok', message: `Using existing KV namespace ${namespaceName}.`, resourceId: namespace.id });
27
- return namespace;
29
+ const existing = await findKvNamespace(client, accountId, namespaceName, configuredNamespaceId);
30
+ if (existing) {
31
+ persistKvNamespace(context, existing, namespaceName, persist);
32
+ steps.push({ name: 'kv-namespace', status: 'ok', message: `Using existing KV namespace ${namespaceName}.`, resourceId: existing.id });
33
+ return existing;
34
+ }
35
+ if (configuredNamespaceId) {
36
+ const configured = { id: configuredNamespaceId, title: namespaceName };
37
+ persistKvNamespace(context, configured, namespaceName, persist);
38
+ steps.push({ name: 'kv-namespace', status: 'ok', message: `Using configured KV namespace ${namespaceName}.`, resourceId: configuredNamespaceId });
39
+ return configured;
40
+ }
41
+ try {
42
+ const created = await client.kv.namespaces.create({ account_id: accountId, title: namespaceName });
43
+ persistKvNamespace(context, created, namespaceName, persist);
44
+ steps.push({ name: 'kv-namespace', status: 'ok', message: `Created KV namespace ${namespaceName}.`, resourceId: created.id });
45
+ return created;
46
+ }
47
+ catch (error) {
48
+ const recovered = await findKvNamespace(client, accountId, namespaceName, configuredNamespaceId);
49
+ if (recovered) {
50
+ persistKvNamespace(context, recovered, namespaceName, persist);
51
+ steps.push({ name: 'kv-namespace', status: 'ok', message: `Using existing KV namespace ${namespaceName} after create retry: ${summarizeError(error)}`, resourceId: recovered.id });
52
+ return recovered;
28
53
  }
54
+ throw error;
29
55
  }
30
- const created = await client.kv.namespaces.create({ account_id: accountId, title: namespaceName });
31
- context.setConfig('cloudflare.kvNamespaceName', namespaceName, persist);
32
- if (created.id)
33
- context.setConfig('cloudflare.kvNamespaceId', created.id, persist);
34
- steps.push({ name: 'kv-namespace', status: 'ok', message: `Created KV namespace ${namespaceName}.`, resourceId: created.id });
35
- return created;
36
56
  }
37
57
  export async function ensureR2Bucket(context, client, accountId, bucketName, persist, steps) {
38
58
  if (!client.r2) {
39
59
  throw new CloudflareControlPlaneError('The Cloudflare client does not expose R2 bucket APIs.', 'CLOUDFLARE_R2_API_UNAVAILABLE', 500);
40
60
  }
41
- const existing = (await client.r2.buckets.list({ account_id: accountId })).buckets?.find((bucket) => bucket.name === bucketName);
61
+ const existing = await findR2BucketByName(client, accountId, bucketName);
42
62
  if (existing) {
43
63
  context.setConfig('cloudflare.r2BucketName', bucketName, persist);
44
64
  steps.push({ name: 'r2-bucket', status: 'ok', message: `Using existing R2 Standard bucket ${bucketName}.`, resourceId: bucketName });
45
65
  return existing;
46
66
  }
47
- const created = await client.r2.buckets.create({ account_id: accountId, name: bucketName, storageClass: 'Standard' });
48
- context.setConfig('cloudflare.r2BucketName', bucketName, persist);
49
- steps.push({ name: 'r2-bucket', status: 'ok', message: `Created R2 Standard bucket ${bucketName}.`, resourceId: bucketName });
50
- return created.name ? created : { ...created, name: bucketName, storage_class: 'Standard' };
67
+ try {
68
+ const created = await client.r2.buckets.create({ account_id: accountId, name: bucketName, storageClass: 'Standard' });
69
+ context.setConfig('cloudflare.r2BucketName', bucketName, persist);
70
+ steps.push({ name: 'r2-bucket', status: 'ok', message: `Created R2 Standard bucket ${bucketName}.`, resourceId: bucketName });
71
+ return created.name ? created : { ...created, name: bucketName, storage_class: 'Standard' };
72
+ }
73
+ catch (error) {
74
+ const recovered = await findR2BucketByName(client, accountId, bucketName);
75
+ if (recovered) {
76
+ context.setConfig('cloudflare.r2BucketName', bucketName, persist);
77
+ steps.push({ name: 'r2-bucket', status: 'ok', message: `Using existing R2 bucket ${bucketName} after create retry: ${summarizeError(error)}`, resourceId: bucketName });
78
+ return recovered;
79
+ }
80
+ throw error;
81
+ }
51
82
  }
52
- export async function ensureSecretsStore(context, client, accountId, storeName, persist, steps) {
83
+ export async function ensureSecretsStore(context, client, accountId, storeName, configuredStoreId, persist, steps) {
53
84
  if (!client.secretsStore) {
54
85
  throw new CloudflareControlPlaneError('The Cloudflare client does not expose Secrets Store APIs.', 'CLOUDFLARE_SECRETS_STORE_API_UNAVAILABLE', 500);
55
86
  }
56
- for await (const store of client.secretsStore.stores.list({ account_id: accountId })) {
57
- if (store.name === storeName) {
58
- context.setConfig('cloudflare.secretsStoreName', storeName, persist);
59
- context.setConfig('cloudflare.secretsStoreId', store.id, persist);
60
- steps.push({ name: 'secrets-store', status: 'ok', message: `Using existing Cloudflare Secrets Store ${storeName}.`, resourceId: store.id });
61
- return store;
87
+ const existing = await findSecretsStore(client, accountId, storeName, configuredStoreId);
88
+ if (existing) {
89
+ persistSecretsStore(context, existing, persist);
90
+ steps.push({ name: 'secrets-store', status: 'ok', message: `Using existing Cloudflare Secrets Store ${existing.name}.`, resourceId: existing.id });
91
+ return existing;
92
+ }
93
+ if (configuredStoreId) {
94
+ const configured = { id: configuredStoreId, name: storeName };
95
+ persistSecretsStore(context, configured, persist);
96
+ steps.push({ name: 'secrets-store', status: 'warning', message: `Using configured Cloudflare Secrets Store id ${configuredStoreId}; it was not visible during discovery.`, resourceId: configuredStoreId });
97
+ return configured;
98
+ }
99
+ try {
100
+ for await (const created of client.secretsStore.stores.create({ account_id: accountId, body: [{ name: storeName }] })) {
101
+ persistSecretsStore(context, created, persist);
102
+ steps.push({ name: 'secrets-store', status: 'ok', message: `Created Cloudflare Secrets Store ${storeName}.`, resourceId: created.id });
103
+ return created;
62
104
  }
63
105
  }
64
- for await (const created of client.secretsStore.stores.create({ account_id: accountId, body: [{ name: storeName }] })) {
65
- context.setConfig('cloudflare.secretsStoreName', storeName, persist);
66
- context.setConfig('cloudflare.secretsStoreId', created.id, persist);
67
- steps.push({ name: 'secrets-store', status: 'ok', message: `Created Cloudflare Secrets Store ${storeName}.`, resourceId: created.id });
68
- return created;
106
+ catch (error) {
107
+ const recovered = await findRecoverableSecretsStore(client, accountId, storeName, configuredStoreId, error);
108
+ if (recovered) {
109
+ persistSecretsStore(context, recovered, persist);
110
+ steps.push({ name: 'secrets-store', status: recovered.name === storeName ? 'ok' : 'warning', message: `Using existing Cloudflare Secrets Store ${recovered.name} after create retry: ${summarizeError(error)}`, resourceId: recovered.id });
111
+ return recovered;
112
+ }
113
+ throw error;
69
114
  }
70
115
  throw new CloudflareControlPlaneError(`Cloudflare Secrets Store '${storeName}' did not return a created store.`, 'CLOUDFLARE_SECRETS_STORE_CREATE_FAILED', 502);
71
116
  }
@@ -86,8 +131,16 @@ export async function ensureTunnel(context, client, input) {
86
131
  }
87
132
  }
88
133
  if (!tunnel) {
89
- tunnel = await api.create({ account_id: input.accountId, name: input.tunnelName, config_src: 'cloudflare' });
90
- input.steps.push({ name: 'zero-trust-tunnel', status: 'ok', message: `Created Zero Trust Tunnel ${input.tunnelName}.`, resourceId: tunnel.id });
134
+ try {
135
+ tunnel = await api.create({ account_id: input.accountId, name: input.tunnelName, config_src: 'cloudflare' });
136
+ input.steps.push({ name: 'zero-trust-tunnel', status: 'ok', message: `Created Zero Trust Tunnel ${input.tunnelName}.`, resourceId: tunnel.id });
137
+ }
138
+ catch (error) {
139
+ tunnel = await findTunnelByName(client, input.accountId, input.tunnelName);
140
+ if (!tunnel)
141
+ throw error;
142
+ input.steps.push({ name: 'zero-trust-tunnel', status: 'ok', message: `Using existing Zero Trust Tunnel ${input.tunnelName} after create retry: ${summarizeError(error)}`, resourceId: tunnel.id });
143
+ }
91
144
  }
92
145
  else {
93
146
  input.steps.push({ name: 'zero-trust-tunnel', status: 'ok', message: `Using existing Zero Trust Tunnel ${input.tunnelName}.`, resourceId: tunnel.id });
@@ -135,8 +188,16 @@ export async function ensureAccess(context, client, input) {
135
188
  }
136
189
  }
137
190
  if (!serviceToken) {
138
- serviceToken = await api.serviceTokens.create({ account_id: input.accountId, name: 'GoodVibes Daemon', duration: '8760h' });
139
- input.steps.push({ name: 'zero-trust-access-service-token', status: 'ok', message: 'Created Zero Trust Access service token.', resourceId: serviceToken.id });
191
+ try {
192
+ serviceToken = await api.serviceTokens.create({ account_id: input.accountId, name: 'GoodVibes Daemon', duration: '8760h' });
193
+ input.steps.push({ name: 'zero-trust-access-service-token', status: 'ok', message: 'Created Zero Trust Access service token.', resourceId: serviceToken.id });
194
+ }
195
+ catch (error) {
196
+ serviceToken = await findAccessServiceTokenByName(api, input.accountId, 'GoodVibes Daemon');
197
+ if (!serviceToken)
198
+ throw error;
199
+ input.steps.push({ name: 'zero-trust-access-service-token', status: 'ok', message: `Using existing Zero Trust Access service token after create retry: ${summarizeError(error)}`, resourceId: serviceToken.id });
200
+ }
140
201
  }
141
202
  else {
142
203
  input.steps.push({ name: 'zero-trust-access-service-token', status: 'ok', message: 'Using existing Zero Trust Access service token.', resourceId: serviceToken.id });
@@ -190,9 +251,20 @@ export async function ensureAccess(context, client, input) {
190
251
  },
191
252
  ],
192
253
  };
193
- app = app?.id
194
- ? await api.applications.update(app.id, accessAppParams)
195
- : await api.applications.create(accessAppParams);
254
+ if (app?.id) {
255
+ app = await api.applications.update(app.id, accessAppParams);
256
+ }
257
+ else {
258
+ try {
259
+ app = await api.applications.create(accessAppParams);
260
+ }
261
+ catch (error) {
262
+ const recovered = await findAccessApplicationByDomain(api, input.accountId, input.daemonHostname);
263
+ if (!recovered?.id)
264
+ throw error;
265
+ app = await api.applications.update(recovered.id, accessAppParams);
266
+ }
267
+ }
196
268
  if (app.id)
197
269
  context.setConfig('cloudflare.accessAppId', app.id, input.persist);
198
270
  input.steps.push({ name: 'zero-trust-access-app', status: 'ok', message: `Configured Zero Trust Access application for ${input.daemonHostname}.`, resourceId: app.id });
@@ -243,63 +315,6 @@ export async function findDurableObjectNamespace(context, client, accountId, nam
243
315
  steps.push({ name: 'durable-object-namespace', status: 'warning', message: 'Durable Object migration was included, but the namespace was not visible yet during confirmation.' });
244
316
  return { name: namespaceName };
245
317
  }
246
- export async function uploadWorker(client, input) {
247
- const file = new File([GOODVIBES_CLOUDFLARE_WORKER_MODULE], 'goodvibes-cloudflare-worker.mjs', { type: 'application/javascript+module' });
248
- const bindings = [
249
- ...(input.queueName ? [{ type: 'queue', name: 'GOODVIBES_BATCH_QUEUE', queue_name: input.queueName }] : []),
250
- { type: 'plain_text', name: 'GOODVIBES_DAEMON_URL', text: input.daemonBaseUrl },
251
- { type: 'plain_text', name: 'GOODVIBES_QUEUE_JOB_PAYLOADS', text: input.queueJobPayloads ? 'true' : 'false' },
252
- ...(input.kvNamespaceId ? [{ type: 'kv_namespace', name: 'GOODVIBES_KV', namespace_id: input.kvNamespaceId }] : []),
253
- ...(input.r2BucketName ? [{ type: 'r2_bucket', name: 'GOODVIBES_ARTIFACTS', bucket_name: input.r2BucketName }] : []),
254
- ...(input.durableObject ? [{ type: 'durable_object_namespace', name: 'GOODVIBES_COORDINATOR', class_name: DEFAULT_DO_NAMESPACE_NAME }] : []),
255
- ];
256
- await client.workers.scripts.update(input.workerName, {
257
- account_id: input.accountId,
258
- metadata: {
259
- main_module: 'goodvibes-cloudflare-worker.mjs',
260
- compatibility_date: '2026-04-25',
261
- bindings,
262
- ...(input.durableObject ? { migrations: { tag: 'goodvibes-coordinator-v1', new_sqlite_classes: [DEFAULT_DO_NAMESPACE_NAME] } } : {}),
263
- keep_bindings: ['secret_text'],
264
- },
265
- files: [file],
266
- });
267
- }
268
- export async function configureWorkerSubdomain(context, client, input) {
269
- if (!input.enableWorkersDev) {
270
- input.steps.push({ name: 'worker-subdomain', status: 'skipped', message: 'workers.dev subdomain enablement was skipped.' });
271
- return clean(input.requestedSubdomain) || context.readConfig().workerSubdomain;
272
- }
273
- let accountSubdomain = clean(input.requestedSubdomain) || context.readConfig().workerSubdomain;
274
- if (accountSubdomain) {
275
- const updated = await client.workers.subdomains.update({ account_id: input.accountId, subdomain: accountSubdomain });
276
- accountSubdomain = updated.subdomain;
277
- context.setConfig('cloudflare.workerSubdomain', accountSubdomain, input.persist);
278
- input.steps.push({ name: 'account-worker-subdomain', status: 'ok', message: `Configured account workers.dev subdomain ${accountSubdomain}.` });
279
- }
280
- else {
281
- try {
282
- const existing = await client.workers.subdomains.get({ account_id: input.accountId });
283
- accountSubdomain = existing.subdomain;
284
- context.setConfig('cloudflare.workerSubdomain', accountSubdomain, input.persist);
285
- input.steps.push({ name: 'account-worker-subdomain', status: 'ok', message: `Using account workers.dev subdomain ${accountSubdomain}.` });
286
- }
287
- catch (error) {
288
- input.steps.push({
289
- name: 'account-worker-subdomain',
290
- status: 'warning',
291
- message: `Could not read account workers.dev subdomain: ${summarizeError(error)}`,
292
- });
293
- }
294
- }
295
- await client.workers.scripts.subdomain.create(input.workerName, {
296
- account_id: input.accountId,
297
- enabled: true,
298
- previews_enabled: false,
299
- });
300
- input.steps.push({ name: 'worker-subdomain', status: 'ok', message: `Enabled workers.dev route for ${input.workerName}.` });
301
- return accountSubdomain;
302
- }
303
318
  export async function ensureQueueConsumer(client, input) {
304
319
  const settings = {
305
320
  batch_size: 10,
@@ -320,15 +335,31 @@ export async function ensureQueueConsumer(client, input) {
320
335
  return updated;
321
336
  }
322
337
  }
323
- const created = await client.queues.consumers.create(input.queueId, {
324
- account_id: input.accountId,
325
- type: 'worker',
326
- script_name: input.workerName,
327
- dead_letter_queue: input.deadLetterQueueName,
328
- settings,
329
- });
330
- input.steps.push({ name: 'queue-consumer', status: 'ok', message: `Created Queue consumer for ${input.workerName}.`, resourceId: created.consumer_id });
331
- return created;
338
+ try {
339
+ const created = await client.queues.consumers.create(input.queueId, {
340
+ account_id: input.accountId,
341
+ type: 'worker',
342
+ script_name: input.workerName,
343
+ dead_letter_queue: input.deadLetterQueueName,
344
+ settings,
345
+ });
346
+ input.steps.push({ name: 'queue-consumer', status: 'ok', message: `Created Queue consumer for ${input.workerName}.`, resourceId: created.consumer_id });
347
+ return created;
348
+ }
349
+ catch (error) {
350
+ const recovered = await findQueueConsumer(client, input.accountId, input.queueId, input.workerName);
351
+ if (!recovered?.consumer_id)
352
+ throw error;
353
+ const updated = await client.queues.consumers.update(input.queueId, recovered.consumer_id, {
354
+ account_id: input.accountId,
355
+ type: 'worker',
356
+ script_name: input.workerName,
357
+ dead_letter_queue: input.deadLetterQueueName,
358
+ settings,
359
+ });
360
+ input.steps.push({ name: 'queue-consumer', status: 'ok', message: `Updated existing Queue consumer for ${input.workerName} after create retry: ${summarizeError(error)}`, resourceId: updated.consumer_id });
361
+ return updated;
362
+ }
332
363
  }
333
364
  async function ensureCnameRecord(client, zoneId, hostname, target, steps, stepName) {
334
365
  const existing = await collectAsync(client.dns.records.list({ zone_id: zoneId, type: 'CNAME', name: { exact: hostname } }));
@@ -347,7 +378,106 @@ async function ensureCnameRecord(client, zoneId, hostname, target, steps, stepNa
347
378
  steps.push({ name: stepName, status: 'ok', message: `Updated CNAME ${hostname} -> ${target}.`, resourceId: updated.id });
348
379
  return updated;
349
380
  }
350
- const created = await client.dns.records.create(params);
351
- steps.push({ name: stepName, status: 'ok', message: `Created CNAME ${hostname} -> ${target}.`, resourceId: created.id });
352
- return created;
381
+ try {
382
+ const created = await client.dns.records.create(params);
383
+ steps.push({ name: stepName, status: 'ok', message: `Created CNAME ${hostname} -> ${target}.`, resourceId: created.id });
384
+ return created;
385
+ }
386
+ catch (error) {
387
+ const recovered = await findCnameRecord(client, zoneId, hostname);
388
+ if (!recovered?.id)
389
+ throw error;
390
+ const updated = await client.dns.records.update(recovered.id, params);
391
+ steps.push({ name: stepName, status: 'ok', message: `Updated existing CNAME ${hostname} -> ${target} after create retry: ${summarizeError(error)}`, resourceId: updated.id });
392
+ return updated;
393
+ }
394
+ }
395
+ async function findQueueByName(client, accountId, queueName) {
396
+ for await (const queue of client.queues.list({ account_id: accountId })) {
397
+ if (queue.queue_name === queueName)
398
+ return queue;
399
+ }
400
+ return undefined;
401
+ }
402
+ async function findKvNamespace(client, accountId, namespaceName, namespaceId) {
403
+ for await (const namespace of client.kv.namespaces.list({ account_id: accountId })) {
404
+ if (namespace.title === namespaceName || (namespaceId && namespace.id === namespaceId))
405
+ return namespace;
406
+ }
407
+ return undefined;
408
+ }
409
+ function persistKvNamespace(context, namespace, namespaceName, persist) {
410
+ context.setConfig('cloudflare.kvNamespaceName', namespace.title ?? namespaceName, persist);
411
+ if (namespace.id)
412
+ context.setConfig('cloudflare.kvNamespaceId', namespace.id, persist);
413
+ }
414
+ async function findR2BucketByName(client, accountId, bucketName) {
415
+ const listed = (await client.r2.buckets.list({ account_id: accountId })).buckets?.find((bucket) => bucket.name === bucketName);
416
+ if (listed)
417
+ return listed;
418
+ if (!client.r2.buckets.get)
419
+ return undefined;
420
+ try {
421
+ const bucket = await client.r2.buckets.get(bucketName, { account_id: accountId });
422
+ return bucket.name ? bucket : { ...bucket, name: bucketName };
423
+ }
424
+ catch {
425
+ return undefined;
426
+ }
427
+ }
428
+ async function findSecretsStore(client, accountId, storeName, storeId) {
429
+ for await (const store of client.secretsStore.stores.list({ account_id: accountId })) {
430
+ if (store.name === storeName || (storeId && store.id === storeId))
431
+ return store;
432
+ }
433
+ return undefined;
434
+ }
435
+ async function findRecoverableSecretsStore(client, accountId, storeName, storeId, error) {
436
+ const stores = await collectAsync(client.secretsStore.stores.list({ account_id: accountId }));
437
+ const exact = stores.find((store) => store.name === storeName || (storeId && store.id === storeId));
438
+ if (exact)
439
+ return exact;
440
+ if (isMaximumStoresExceeded(error) && stores.length === 1)
441
+ return stores[0];
442
+ return undefined;
443
+ }
444
+ function persistSecretsStore(context, store, persist) {
445
+ context.setConfig('cloudflare.secretsStoreName', store.name, persist);
446
+ context.setConfig('cloudflare.secretsStoreId', store.id, persist);
447
+ }
448
+ function isMaximumStoresExceeded(error) {
449
+ return summarizeError(error).toLowerCase().includes('maximum_stores_exceeded');
450
+ }
451
+ async function findTunnelByName(client, accountId, tunnelName) {
452
+ const api = client.zeroTrust.tunnels.cloudflared;
453
+ for await (const tunnel of api.list({ account_id: accountId, name: tunnelName, is_deleted: false })) {
454
+ if (tunnel.name === tunnelName)
455
+ return tunnel;
456
+ }
457
+ return undefined;
458
+ }
459
+ async function findAccessServiceTokenByName(api, accountId, name) {
460
+ for await (const token of api.serviceTokens.list({ account_id: accountId, name })) {
461
+ if (token.name === name)
462
+ return token;
463
+ }
464
+ return undefined;
465
+ }
466
+ async function findAccessApplicationByDomain(api, accountId, domain) {
467
+ for await (const app of api.applications.list({ account_id: accountId, domain, exact: true })) {
468
+ if (app.domain === domain)
469
+ return app;
470
+ }
471
+ return undefined;
472
+ }
473
+ async function findQueueConsumer(client, accountId, queueId, workerName) {
474
+ for await (const consumer of client.queues.consumers.list(queueId, { account_id: accountId })) {
475
+ if (consumer.type === 'worker' && consumer.script === workerName)
476
+ return consumer;
477
+ }
478
+ return undefined;
479
+ }
480
+ async function findCnameRecord(client, zoneId, hostname) {
481
+ const existing = await collectAsync(client.dns.records.list({ zone_id: zoneId, type: 'CNAME', name: { exact: hostname } }));
482
+ return existing.find((record) => record.name === hostname && record.type === 'CNAME');
353
483
  }
@@ -0,0 +1,29 @@
1
+ import type { CloudflareApiClient, CloudflareProvisionStep } from './types.js';
2
+ import type { CloudflareProvisioningContext } from './resources.js';
3
+ export declare function uploadWorker(client: CloudflareApiClient, input: {
4
+ readonly accountId: string;
5
+ readonly workerName: string;
6
+ readonly queueName: string;
7
+ readonly daemonBaseUrl: string;
8
+ readonly queueJobPayloads: boolean;
9
+ readonly kvNamespaceId: string;
10
+ readonly r2BucketName: string;
11
+ readonly durableObject: boolean;
12
+ }): Promise<void>;
13
+ export declare function configureWorkerSubdomain(context: CloudflareProvisioningContext, client: CloudflareApiClient, input: {
14
+ readonly accountId: string;
15
+ readonly workerName: string;
16
+ readonly requestedSubdomain?: string;
17
+ readonly enableWorkersDev: boolean;
18
+ readonly steps: CloudflareProvisionStep[];
19
+ readonly persist: boolean;
20
+ }): Promise<string>;
21
+ export declare function configureWorkerSchedule(client: CloudflareApiClient, input: {
22
+ readonly accountId: string;
23
+ readonly workerName: string;
24
+ readonly workerCron: string;
25
+ readonly steps: CloudflareProvisionStep[];
26
+ }): Promise<void>;
27
+ export declare function disableWorkerSchedule(client: CloudflareApiClient, accountId: string, workerName: string, steps: CloudflareProvisionStep[]): Promise<void>;
28
+ export declare function disableWorkerSubdomain(client: CloudflareApiClient, accountId: string, workerName: string, steps: CloudflareProvisionStep[]): Promise<void>;
29
+ //# sourceMappingURL=worker-settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-settings.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/cloudflare/worker-settings.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAGpB,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAEpE,wBAAsB,YAAY,CAChC,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE;IACL,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC,GACA,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,6BAA6B,EACtC,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE;IACL,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,uBAAuB,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,GACA,OAAO,CAAC,MAAM,CAAC,CA4DjB;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE;IACL,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,uBAAuB,EAAE,CAAC;CAC3C,GACA,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,mBAAmB,EAC3B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,uBAAuB,EAAE,GAC/B,OAAO,CAAC,IAAI,CAAC,CAYf;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,uBAAuB,EAAE,GAC/B,OAAO,CAAC,IAAI,CAAC,CAYf"}
@@ -0,0 +1,146 @@
1
+ import { summarizeError } from '../utils/error-display.js';
2
+ import { DEFAULT_DO_NAMESPACE_NAME } from './constants.js';
3
+ import { clean } from './utils.js';
4
+ import { GOODVIBES_CLOUDFLARE_WORKER_MODULE } from './worker-source.js';
5
+ export async function uploadWorker(client, input) {
6
+ const file = new File([GOODVIBES_CLOUDFLARE_WORKER_MODULE], 'goodvibes-cloudflare-worker.mjs', { type: 'application/javascript+module' });
7
+ const bindings = [
8
+ ...(input.queueName ? [{ type: 'queue', name: 'GOODVIBES_BATCH_QUEUE', queue_name: input.queueName }] : []),
9
+ { type: 'plain_text', name: 'GOODVIBES_DAEMON_URL', text: input.daemonBaseUrl },
10
+ { type: 'plain_text', name: 'GOODVIBES_QUEUE_JOB_PAYLOADS', text: input.queueJobPayloads ? 'true' : 'false' },
11
+ ...(input.kvNamespaceId ? [{ type: 'kv_namespace', name: 'GOODVIBES_KV', namespace_id: input.kvNamespaceId }] : []),
12
+ ...(input.r2BucketName ? [{ type: 'r2_bucket', name: 'GOODVIBES_ARTIFACTS', bucket_name: input.r2BucketName }] : []),
13
+ ...(input.durableObject ? [{ type: 'durable_object_namespace', name: 'GOODVIBES_COORDINATOR', class_name: DEFAULT_DO_NAMESPACE_NAME }] : []),
14
+ ];
15
+ await client.workers.scripts.update(input.workerName, {
16
+ account_id: input.accountId,
17
+ metadata: {
18
+ main_module: 'goodvibes-cloudflare-worker.mjs',
19
+ compatibility_date: '2026-04-25',
20
+ bindings,
21
+ ...(input.durableObject ? { migrations: { tag: 'goodvibes-coordinator-v1', new_sqlite_classes: [DEFAULT_DO_NAMESPACE_NAME] } } : {}),
22
+ keep_bindings: ['secret_text'],
23
+ },
24
+ files: [file],
25
+ });
26
+ }
27
+ export async function configureWorkerSubdomain(context, client, input) {
28
+ const requested = clean(input.requestedSubdomain) || context.readConfig().workerSubdomain;
29
+ if (!input.enableWorkersDev) {
30
+ input.steps.push({ name: 'worker-subdomain', status: 'skipped', message: 'workers.dev subdomain enablement was skipped.' });
31
+ return requested;
32
+ }
33
+ let accountSubdomain = await readAccountWorkerSubdomain(client, input.accountId);
34
+ if (accountSubdomain) {
35
+ context.setConfig('cloudflare.workerSubdomain', accountSubdomain, input.persist);
36
+ input.steps.push({
37
+ name: 'account-worker-subdomain',
38
+ status: requested && requested !== accountSubdomain ? 'warning' : 'ok',
39
+ message: requested && requested !== accountSubdomain
40
+ ? `Using existing account workers.dev subdomain ${accountSubdomain}; requested ${requested} was ignored because the account already has an associated subdomain.`
41
+ : `Using account workers.dev subdomain ${accountSubdomain}.`,
42
+ });
43
+ }
44
+ else if (requested) {
45
+ try {
46
+ const updated = await client.workers.subdomains.update({ account_id: input.accountId, subdomain: requested });
47
+ accountSubdomain = clean(updated.subdomain) || requested;
48
+ context.setConfig('cloudflare.workerSubdomain', accountSubdomain, input.persist);
49
+ input.steps.push({ name: 'account-worker-subdomain', status: 'ok', message: `Configured account workers.dev subdomain ${accountSubdomain}.` });
50
+ }
51
+ catch (error) {
52
+ const recovered = await readAccountWorkerSubdomain(client, input.accountId);
53
+ if (!recovered)
54
+ throw error;
55
+ accountSubdomain = recovered;
56
+ context.setConfig('cloudflare.workerSubdomain', accountSubdomain, input.persist);
57
+ input.steps.push({
58
+ name: 'account-worker-subdomain',
59
+ status: requested === recovered ? 'ok' : 'warning',
60
+ message: `Using existing account workers.dev subdomain ${accountSubdomain} after configure retry: ${summarizeError(error)}`,
61
+ });
62
+ }
63
+ }
64
+ else {
65
+ input.steps.push({ name: 'account-worker-subdomain', status: 'warning', message: 'No account workers.dev subdomain is configured.' });
66
+ }
67
+ try {
68
+ const existing = await client.workers.scripts.subdomain.get(input.workerName, { account_id: input.accountId });
69
+ if (existing.enabled) {
70
+ input.steps.push({ name: 'worker-subdomain', status: 'ok', message: `Using existing workers.dev route for ${input.workerName}.` });
71
+ return accountSubdomain;
72
+ }
73
+ }
74
+ catch {
75
+ // Older accounts may not return script-level subdomain state before it is enabled.
76
+ }
77
+ try {
78
+ await client.workers.scripts.subdomain.create(input.workerName, {
79
+ account_id: input.accountId,
80
+ enabled: true,
81
+ previews_enabled: false,
82
+ });
83
+ input.steps.push({ name: 'worker-subdomain', status: 'ok', message: `Enabled workers.dev route for ${input.workerName}.` });
84
+ }
85
+ catch (error) {
86
+ const recovered = await client.workers.scripts.subdomain.get(input.workerName, { account_id: input.accountId });
87
+ if (!recovered.enabled)
88
+ throw error;
89
+ input.steps.push({ name: 'worker-subdomain', status: 'ok', message: `Using existing workers.dev route for ${input.workerName} after enable retry: ${summarizeError(error)}` });
90
+ }
91
+ return accountSubdomain;
92
+ }
93
+ export async function configureWorkerSchedule(client, input) {
94
+ const body = [{ cron: input.workerCron }];
95
+ try {
96
+ const existing = await client.workers.scripts.schedules.get(input.workerName, { account_id: input.accountId });
97
+ if (sameSchedules(existing.schedules, body)) {
98
+ input.steps.push({ name: 'configure-cron', status: 'ok', message: `Using existing Worker cron ${input.workerCron}.` });
99
+ return;
100
+ }
101
+ }
102
+ catch {
103
+ // Some accounts return 404 until the script has its first schedule.
104
+ }
105
+ await client.workers.scripts.schedules.update(input.workerName, { account_id: input.accountId, body });
106
+ input.steps.push({ name: 'configure-cron', status: 'ok', message: `Configured Worker cron ${input.workerCron}.` });
107
+ }
108
+ export async function disableWorkerSchedule(client, accountId, workerName, steps) {
109
+ try {
110
+ const existing = await client.workers.scripts.schedules.get(workerName, { account_id: accountId });
111
+ if (existing.schedules.length === 0) {
112
+ steps.push({ name: 'disable-cron', status: 'skipped', message: `No Worker cron schedules were configured for ${workerName}.` });
113
+ return;
114
+ }
115
+ }
116
+ catch {
117
+ // Keep disable best-effort: if state cannot be read, clear schedules anyway.
118
+ }
119
+ await client.workers.scripts.schedules.update(workerName, { account_id: accountId, body: [] });
120
+ steps.push({ name: 'disable-cron', status: 'ok', message: `Removed Worker cron schedules from ${workerName}.` });
121
+ }
122
+ export async function disableWorkerSubdomain(client, accountId, workerName, steps) {
123
+ try {
124
+ const existing = await client.workers.scripts.subdomain.get(workerName, { account_id: accountId });
125
+ if (!existing.enabled) {
126
+ steps.push({ name: 'disable-worker-subdomain', status: 'skipped', message: `workers.dev route was already disabled for ${workerName}.` });
127
+ return;
128
+ }
129
+ }
130
+ catch {
131
+ // Keep disable best-effort: if state cannot be read, attempt deletion.
132
+ }
133
+ await client.workers.scripts.subdomain.delete(workerName, { account_id: accountId });
134
+ steps.push({ name: 'disable-worker-subdomain', status: 'ok', message: `Disabled workers.dev route for ${workerName}.` });
135
+ }
136
+ async function readAccountWorkerSubdomain(client, accountId) {
137
+ try {
138
+ return clean((await client.workers.subdomains.get({ account_id: accountId })).subdomain);
139
+ }
140
+ catch {
141
+ return '';
142
+ }
143
+ }
144
+ function sameSchedules(actual, expected) {
145
+ return actual.length === expected.length && actual.every((schedule, index) => schedule.cron === expected[index]?.cron);
146
+ }
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- let version = '0.25.17';
3
+ let version = '0.25.19';
4
4
  try {
5
5
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', '..', 'package.json'), 'utf-8'));
6
6
  version = pkg.version ?? version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-sdk",
3
- "version": "0.25.17",
3
+ "version": "0.25.19",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/mgd34msu/goodvibes-sdk.git"