@camstack/addon-google-services 0.2.42 → 0.2.43

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,5 +1,5 @@
1
1
  import { createHash, randomBytes } from "node:crypto";
2
- //#region ../types/dist/event-category-BmPm98n0.mjs
2
+ //#region ../types/dist/event-category-78tcBemo.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -120,6 +120,23 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
120
120
  */
121
121
  EventCategory["AddonLoadRecovered"] = "addon.load-recovered";
122
122
  /**
123
+ * An addon is RUNNING although its installed package is below what the
124
+ * running server requires (`camstack.requires.addons` of the server, or the
125
+ * addon's own `requires.server`). Raised once per streak by the unsupported-
126
+ * addon tracker, on the hub and on agents; AlertCenter turns it into one
127
+ * operator alert per node and package. The addon is never held back for it.
128
+ *
129
+ * Payload: `{ packageName, addonId, nodeId, installedVersion, requiredMinimum, serverVersion, unmet }`.
130
+ */
131
+ EventCategory["AddonUnsupportedVersion"] = "addon.unsupported-version";
132
+ /**
133
+ * The package of an {@link AddonUnsupportedVersion} alert reached a supported
134
+ * version, or is no longer installed on the node. AlertCenter dismisses the matching alert.
135
+ *
136
+ * Payload: `{ packageName, addonId, nodeId }`.
137
+ */
138
+ EventCategory["AddonUnsupportedResolved"] = "addon.unsupported-resolved";
139
+ /**
123
140
  * Monitor scheduled the next retry for a failed addon. Transient —
124
141
  * surfaced to the UI for live-updating the "next retry in Ns"
125
142
  * countdown on the Addons page row, NOT persisted as an alert.
@@ -230,7 +247,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
230
247
  EventCategory["ProcessRestarted"] = "process.restarted";
231
248
  /**
232
249
  * The SET of storage locations changed — one was created, edited, enabled,
233
- * disabled or deleted through `storage.upsertLocation` / `deleteLocation`.
250
+ * disabled or deleted through the location instances or the forced-delete action.
234
251
  *
235
252
  * Telemetry, not a transaction (D8/D11): every consumer that re-resolves on
236
253
  * it must also converge on its own periodic path, because a dropped event
@@ -5981,7 +5998,7 @@ var ZodIssueCode = {
5981
5998
  var ZodFirstPartyTypeKind;
5982
5999
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5983
6000
  //#endregion
5984
- //#region ../types/dist/sleep-D7ZKm4nb.mjs
6001
+ //#region ../types/dist/sleep-AEnTN3b4.mjs
5985
6002
  /**
5986
6003
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5987
6004
  * window to float samples (D455).
@@ -7230,17 +7247,35 @@ var RecordIntegrationInstances = class {
7230
7247
  ...kind !== void 0 ? { kind } : {}
7231
7248
  });
7232
7249
  if (minted === void 0) throw new Error("createInstance needs an id: this provider does not mint one");
7250
+ const initial = this.hooks.initialBody(name, kind);
7251
+ const patch = this.patchOf(values ?? {});
7252
+ if (Object.keys(patch).length > 0) Object.assign(patch, await this.hooks.validateWrite?.({
7253
+ kind,
7254
+ body: {
7255
+ ...initial,
7256
+ ...patch
7257
+ }
7258
+ }));
7233
7259
  await this.handle.put({
7234
7260
  id: minted,
7235
- data: this.hooks.initialBody(name, kind)
7261
+ data: initial
7236
7262
  }, { ifRev: 0 });
7237
- const patch = this.patchOf(values ?? {});
7238
7263
  if (Object.keys(patch).length > 0) await this.handle.patch(minted, patch);
7239
7264
  await this.hooks.onChanged?.(minted, "created");
7240
7265
  return { id: minted };
7241
7266
  };
7242
7267
  updateInstance = async ({ id, name, values }) => {
7243
7268
  const patch = this.patchOf(values);
7269
+ if (this.hooks.validateWrite !== void 0 && Object.keys(patch).length > 0) {
7270
+ const stored = await this.handle.get(id);
7271
+ if (stored !== null) Object.assign(patch, await this.hooks.validateWrite({
7272
+ kind: void 0,
7273
+ body: {
7274
+ ...stored.data,
7275
+ ...patch
7276
+ }
7277
+ }));
7278
+ }
7244
7279
  if (name !== void 0) patch[this.nameField] = name;
7245
7280
  await this.handle.patch(id, patch);
7246
7281
  await this.hooks.onChanged?.(id, "updated");
@@ -10582,7 +10617,6 @@ var CAP_NAMES = Object.freeze([
10582
10617
  "notifier",
10583
10618
  "numeric-sensor",
10584
10619
  "oauth-integration",
10585
- "oidc-connections",
10586
10620
  "osd",
10587
10621
  "osd-manager",
10588
10622
  "pet-feeder",
@@ -12474,8 +12508,7 @@ Object.freeze({
12474
12508
  "device-provider": { "reloadDevice": 18e4 },
12475
12509
  "llm": {
12476
12510
  "generate": 6e5,
12477
- "generateVision": 6e5,
12478
- "testProfile": 6e5
12511
+ "generateVision": 6e5
12479
12512
  },
12480
12513
  "llm-runtime": {
12481
12514
  "complete": 6e5,
@@ -14100,17 +14133,18 @@ function composeInstanceKinds(parts, base) {
14100
14133
  * message to what the kind supports — callers never special-case a service.
14101
14134
  *
14102
14135
  * DESIGN DECISIONS (locked):
14103
- * - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
14104
- * `setTargetEnabled`), each provider persisting via the `settings-store`
14105
- * cap. Rationale: the admin UI needs one uniform surface across the
14106
- * notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
14107
- * alternative would fork the UI per addon and cannot host the
14108
- * discovery→adopt flow.
14109
- * - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
14110
- * the generated cap-mount auto-`concatCollection`-fans them across every
14111
- * registered provider (notifiers addon + HA addon) so one catalog is
14112
- * routable. `send` / `testTarget` / CRUD route to ONE provider by the
14113
- * `addonId` the generated collection router extracts from the call input.
14136
+ * - A target is an INSTANCE of this function cap (epic #440, step 6): the
14137
+ * providers serve their targets as `integration-instances` records, one
14138
+ * record kind per target kind, and the admin lists, adds, edits, switches
14139
+ * and deletes them through that cap. This cap keeps what an instance cannot
14140
+ * say: the kind catalogue (`listTargetKinds`: capabilities, delivery
14141
+ * parameters, brand icon), dispatch (`send`, `testTarget`) and the form
14142
+ * helpers (`discoverTargets`, `probeTargetConfig`).
14143
+ * - `listTargetKinds` / `discoverTargets` return arrays → the generated
14144
+ * cap-mount auto-`concatCollection`-fans them across every registered
14145
+ * provider so one catalog is routable. `send` / `testTarget` /
14146
+ * `probeTargetConfig` route to ONE provider by the `addonId` the generated
14147
+ * collection router extracts from the call input.
14114
14148
  * - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
14115
14149
  * transformer) + UDS MsgPack both round-trip typed arrays — already used by
14116
14150
  * `storage` / `storage-provider` / `recording` caps over the same path. No
@@ -14355,7 +14389,7 @@ var TargetKindCapsSchema = object({
14355
14389
  * the union is large and not meant for runtime validation here; the exported
14356
14390
  * `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
14357
14391
  */
14358
- var ConfigSchemaPassthrough$4 = unknown();
14392
+ var ConfigSchemaPassthrough$3 = unknown();
14359
14393
  var TargetKindSchema = object({
14360
14394
  kind: string(),
14361
14395
  label: string(),
@@ -14392,7 +14426,7 @@ var TargetKindSchema = object({
14392
14426
  * its raster path, which is the safe default for an unknown image.
14393
14427
  */
14394
14428
  iconMediaType: string().optional(),
14395
- configSchema: ConfigSchemaPassthrough$4,
14429
+ configSchema: ConfigSchemaPassthrough$3,
14396
14430
  /**
14397
14431
  * The config keys that decide WHERE this kind's secrets are sent (server,
14398
14432
  * base URL, instance, chat, recipient). A save that changes any of them
@@ -14414,9 +14448,11 @@ var TargetKindSchema = object({
14414
14448
  caps: TargetKindCapsSchema
14415
14449
  });
14416
14450
  /**
14417
- * A persisted target. `config` holds secrets; providers REDACT secret fields
14418
- * (return a presence marker only) when serving `listTargets` — never
14419
- * round-trip a stored secret to the UI.
14451
+ * A target as a provider's own code sees it (the notification-center bridge, the
14452
+ * send path): the flat record body split into the name, the switch and the
14453
+ * kind's fields. `config` holds secrets; a reader that serves it to a client
14454
+ * REDACTS secret fields (a presence marker only) — never round-trip a stored
14455
+ * secret to the UI.
14420
14456
  */
14421
14457
  var TargetSchema = object({
14422
14458
  id: string(),
@@ -14459,13 +14495,13 @@ var ProbeTargetConfigResultSchema = object({
14459
14495
  stateInstance: string().optional(),
14460
14496
  error: string().optional()
14461
14497
  });
14462
- method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
14498
+ method(object({}), array(TargetKindSchema)), method(object({
14463
14499
  kind: string(),
14464
14500
  config: record(string(), unknown()).optional(),
14465
14501
  /**
14466
14502
  * When editing / duplicating, the blank password field never round-trips
14467
14503
  * the stored token. Pass the source target id so the provider can restore
14468
- * secrets server-side before dialling (same merge as upsert).
14504
+ * secrets server-side before dialling.
14469
14505
  */
14470
14506
  targetId: string().optional()
14471
14507
  }), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
@@ -14488,27 +14524,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
14488
14524
  }), TestResultSchema, {
14489
14525
  kind: "mutation",
14490
14526
  auth: "admin"
14491
- }), method(object({
14492
- target: TargetSchema,
14493
- /**
14494
- * Duplicate flow: create a NEW target id while copying secrets from an
14495
- * existing row. The UI never holds the stored token; blank / redacted
14496
- * password fields are restored from this source (D634 still applies if
14497
- * destinations diverge without a re-typed secret).
14498
- */
14499
- cloneSecretsFrom: string().optional()
14500
- }), TargetSchema, {
14501
- kind: "mutation",
14502
- auth: "admin"
14503
- }), method(object({ targetId: string() }), _void(), {
14504
- kind: "mutation",
14505
- auth: "admin"
14506
- }), method(object({
14507
- targetId: string(),
14508
- enabled: boolean()
14509
- }), _void(), {
14510
- kind: "mutation",
14511
- auth: "admin"
14512
14527
  });
14513
14528
  looseObject({
14514
14529
  name: string().min(1),
@@ -22776,7 +22791,6 @@ var SYSTEM_CAP_VOCABULARY = {
22776
22791
  "notification-output": system("notification delivery — reached through notifier devices and rules"),
22777
22792
  "notification-rules": system("notification rules — authored on their own page"),
22778
22793
  "oauth-integration": system(IDENTITY),
22779
- "oidc-connections": system(IDENTITY),
22780
22794
  "osd-manager": system(PIPELINE),
22781
22795
  "pipeline-executor": system(PIPELINE),
22782
22796
  "pipeline-orchestrator": system(PIPELINE),
@@ -54511,7 +54525,7 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
54511
54525
  * or the redaction token KEEPS the stored secret; `{ $secretClear: true }`
54512
54526
  * clears it.
54513
54527
  */
54514
- var ConfigSchemaPassthrough$3 = custom();
54528
+ var ConfigSchemaPassthrough$2 = custom();
54515
54529
  var IntegrationInstanceIdSchema = string().min(1);
54516
54530
  var IntegrationInstanceModeSchema = _enum(["single", "multiple"]);
54517
54531
  /**
@@ -54557,7 +54571,16 @@ var IntegrationInstanceKindSchema = object({
54557
54571
  /** Relative hub path to start an interactive account link of an instance of this kind. */
54558
54572
  connectPath: string().min(1).optional(),
54559
54573
  /** Relative hub path to disconnect that account. */
54560
- disconnectPath: string().min(1).optional()
54574
+ disconnectPath: string().min(1).optional(),
54575
+ /**
54576
+ * Parts of the edit dialog the flat form cannot draw (a node picker, a model source), named by a
54577
+ * GENERIC widget id the client maps to a component; a client that knows none of them shows none.
54578
+ * `connection` widgets write connection values, `model` widgets own the model choice.
54579
+ */
54580
+ widgets: array(object({
54581
+ id: string().min(1),
54582
+ placement: _enum(["connection", "model"])
54583
+ })).optional()
54561
54584
  });
54562
54585
  /**
54563
54586
  * How devices of an instance are found. `none`: the operator adds them by hand; `lan`: the addon
@@ -54662,7 +54685,7 @@ var integrationInstancesCapability = {
54662
54685
  id: IntegrationInstanceIdSchema.nullable(),
54663
54686
  /** The kind of the create form (`id: null`) of a provider with several. */
54664
54687
  kind: string().min(1).optional()
54665
- }), ConfigSchemaPassthrough$3, { auth: "admin" }),
54688
+ }), ConfigSchemaPassthrough$2, { auth: "admin" }),
54666
54689
  listInstances: method(_void(), array(IntegrationInstanceSchema).readonly(), { auth: "admin" }),
54667
54690
  getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), { auth: "admin" }),
54668
54691
  /**
@@ -55613,12 +55636,12 @@ var LlmModelInfoSchema = object({
55613
55636
  });
55614
55637
  /**
55615
55638
  * The provider-specific part of a profile, validated by the provider that owns
55616
- * the kind (`upsertProfile` refuses what it does not accept). A field its
55639
+ * the kind (saving an instance refuses what it does not accept). A field its
55617
55640
  * `connectionSchema` declares `type: 'password'` is a secret: it is held in the
55618
55641
  * keychain, never in the row, and reads back as the redaction marker.
55619
55642
  */
55620
55643
  var LlmProviderConfigSchema = record(string(), unknown());
55621
- var LlmProfileSchema = object({
55644
+ object({
55622
55645
  id: string(),
55623
55646
  name: string(),
55624
55647
  /** The provider-declared kind (`LlmProfileKindDescriptor.kind`). */
@@ -55712,8 +55735,8 @@ var LlmProviderWidgetSchema = object({
55712
55735
  /** ConfigUISchema tree passed through untyped on the wire (the
55713
55736
  * notification-output `ConfigSchemaPassthrough` precedent at
55714
55737
  * notification-output.cap.ts:151); the exported TS type re-tightens it. */
55715
- var ConfigSchemaPassthrough$2 = unknown();
55716
- var LlmProfileKindDescriptorSchema = object({
55738
+ var ConfigSchemaPassthrough$1 = unknown();
55739
+ object({
55717
55740
  kind: LlmProfileKindSchema,
55718
55741
  label: string(),
55719
55742
  /** A generic icon name (`cloud`, `plug`, `cpu`) — never a glyph or a logo. */
@@ -55721,9 +55744,9 @@ var LlmProfileKindDescriptorSchema = object({
55721
55744
  /** Stamped by each provider so the concat-fanned catalog stays routable. */
55722
55745
  addonId: string(),
55723
55746
  /** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
55724
- connectionSchema: ConfigSchemaPassthrough$2,
55747
+ connectionSchema: ConfigSchemaPassthrough$1,
55725
55748
  /** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
55726
- advancedSchema: ConfigSchemaPassthrough$2.optional(),
55749
+ advancedSchema: ConfigSchemaPassthrough$1.optional(),
55727
55750
  /** The kind's defaults; a model from `listModels` may override any of them. */
55728
55751
  features: LlmModelFeaturesSchema,
55729
55752
  /** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
@@ -55852,20 +55875,7 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, {
55852
55875
  }), method(object({
55853
55876
  addonId: string().optional(),
55854
55877
  requestId: string()
55855
- }), _void(), { kind: "mutation" }), method(object({}), array(LlmProfileKindDescriptorSchema)), method(object({}), array(LlmProfileSchema)), method(object({ profile: LlmProfileSchema }), LlmProfileSchema, {
55856
- kind: "mutation",
55857
- auth: "admin"
55858
- }), method(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
55859
- kind: "mutation",
55860
- auth: "admin"
55861
- }), method(ProfileRefInputSchema, _void(), {
55862
- kind: "mutation",
55863
- auth: "admin"
55864
- }), method(ProfileRefInputSchema, LlmGenerateResultSchema, {
55865
- kind: "mutation",
55866
- auth: "admin",
55867
- timeoutMs: AI_CAP_TRANSPORT_TIMEOUT_MS
55868
- }), method(LlmListModelsInputSchema, LlmListModelsResultSchema, {
55878
+ }), _void(), { kind: "mutation" }), method(LlmListModelsInputSchema, LlmListModelsResultSchema, {
55869
55879
  kind: "mutation",
55870
55880
  auth: "admin"
55871
55881
  }), method(object({}), array(LlmDefaultSchema)), method(object({
@@ -56860,20 +56870,7 @@ method(_void(), MeshStatusSchema), method(object({
56860
56870
  /** Optional hostname override the host should advertise once joined. */
56861
56871
  hostname: string().optional() }), object({
56862
56872
  /** Authentication URL the operator should open in a browser. */
56863
- loginUrl: string() }), { kind: "mutation" }), method(_void(), object({ left: literal(true) }), { kind: "mutation" }), method(_void(), object({ loggedOut: literal(true) }), { kind: "mutation" }), method(_void(), object({ peers: array(MeshPeerSchema).readonly() })), method(object({
56864
- /** Optional auth key — when provided, probes the key validity
56865
- * against the provider's API. Omit when already joined to
56866
- * just ping the daemon. */
56867
- authKey: string().optional() }), object({
56868
- ok: boolean(),
56869
- /** Provider-side identifier resolved by the probe (tailnet
56870
- * name for Tailscale, network id for ZeroTier, etc.). */
56871
- tenant: string().optional(),
56872
- /** Daemon binary version, when reachable. */
56873
- daemonVersion: string().optional(),
56874
- /** Human-readable error when `ok: false`. */
56875
- error: string().optional()
56876
- }), { kind: "mutation" });
56873
+ loginUrl: string() }), { kind: "mutation" }), method(_void(), object({ left: literal(true) }), { kind: "mutation" }), method(_void(), object({ loggedOut: literal(true) }), { kind: "mutation" }), method(_void(), object({ peers: array(MeshPeerSchema).readonly() }));
56877
56874
  object({
56878
56875
  value: number().nullable().meta(readingMeta("device", { label: "Total" })),
56879
56876
  lastFetchedAt: number()
@@ -66531,61 +66528,6 @@ var OauthIntegrationDescriptorSchema = object({
66531
66528
  });
66532
66529
  method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
66533
66530
  /**
66534
- * `oidc-connections` — CRUD for IdP rows under `auth-oidc` (D828 sibling).
66535
- *
66536
- * One hub-only singleton (`auth-oidc`). The Settings UI is a DataTable +
66537
- * ItemFormDialog; there is no `editable-array` in `globalSettingsSchema`.
66538
- * Operator-chosen `id` is the URL slug (`/addon/auth-oidc/<id>/…`) and is
66539
- * immutable after create.
66540
- */
66541
- var ConfigSchemaPassthrough$1 = unknown();
66542
- var OidcConnectionSchema = object({
66543
- id: string().min(1),
66544
- displayName: string(),
66545
- icon: string(),
66546
- issuerUrl: string(),
66547
- clientId: string(),
66548
- /** Client id + secret present — never the secret value. */
66549
- configured: boolean(),
66550
- /**
66551
- * Values for the connection form schema. `clientSecret` is a keychain
66552
- * {@link SecretFieldView} or `null` / `''`, never plaintext (D789).
66553
- */
66554
- formValues: record(string(), unknown()).optional()
66555
- });
66556
- /**
66557
- * Patch one connection. Omitted or empty `clientSecret` keeps the stored
66558
- * secret (D787). `{ $secretClear: true }` clears it. `id` is never renamed.
66559
- */
66560
- var OidcConnectionUpdateInputSchema = object({
66561
- id: string().min(1),
66562
- displayName: string().min(1),
66563
- icon: string().optional(),
66564
- issuerUrl: string().optional(),
66565
- clientId: string().optional(),
66566
- clientSecret: union([string(), object({ $secretClear: literal(true) })]).optional(),
66567
- redirectUri: string().optional(),
66568
- scopes: string().optional(),
66569
- usernameClaim: _enum([
66570
- "preferred_username",
66571
- "email",
66572
- "sub"
66573
- ]).optional()
66574
- });
66575
- method(object({}), ConfigSchemaPassthrough$1, { auth: "admin" }), method(object({}), array(OidcConnectionSchema).readonly(), { auth: "admin" }), method(object({
66576
- id: string().min(1).regex(/^[a-z0-9][a-z0-9-]{0,63}$/, "id must be a lowercase slug"),
66577
- displayName: string().min(1)
66578
- }), object({ id: string() }), {
66579
- kind: "mutation",
66580
- auth: "admin"
66581
- }), method(OidcConnectionUpdateInputSchema, object({ ok: literal(true) }), {
66582
- kind: "mutation",
66583
- auth: "admin"
66584
- }), method(object({ id: string().min(1) }), object({ ok: literal(true) }), {
66585
- kind: "mutation",
66586
- auth: "admin"
66587
- });
66588
- /**
66589
66531
  * Generic on-screen-display (video overlay) cap. Each camera exposes
66590
66532
  * a firmware-defined list of overlays (channel name, timestamp,
66591
66533
  * watermark, logo, …); the cap models them as a homogeneous array of
@@ -72771,21 +72713,6 @@ method(object({
72771
72713
  */
72772
72714
  ttlSec: union([number().int().positive(), literal("never")]).optional()
72773
72715
  }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
72774
- var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
72775
- providerId: string().min(1),
72776
- displayName: string().min(1),
72777
- configSchema: unknown(),
72778
- nodeLocal: boolean(),
72779
- shouldSaveDiskSpace: literal(true),
72780
- minFreePercent: number().min(0).max(100)
72781
- }), object({
72782
- providerId: string().min(1),
72783
- displayName: string().min(1),
72784
- configSchema: unknown(),
72785
- nodeLocal: boolean(),
72786
- shouldSaveDiskSpace: literal(false),
72787
- minFreePercent: literal(null)
72788
- })]);
72789
72716
  method(object({
72790
72717
  location: StorageLocationRefSchema,
72791
72718
  relativePath: string()
@@ -72847,42 +72774,7 @@ method(object({
72847
72774
  }), _instanceof(Uint8Array), { auth: "admin" }), method(object({ downloadId: string() }), _void(), {
72848
72775
  kind: "mutation",
72849
72776
  auth: "admin"
72850
- }), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(StorageLocationSchema.omit({
72851
- createdAt: true,
72852
- updatedAt: true
72853
- }), StorageLocationSchema, {
72854
- kind: "mutation",
72855
- auth: "admin"
72856
- }), method(object({
72857
- id: string(),
72858
- force: boolean().optional()
72859
- }), _void(), {
72860
- kind: "mutation",
72861
- auth: "admin"
72862
- }), method(_void(), array(StorageDrainProgressSchema).readonly()), method(object({ id: string() }), object({
72863
- ok: boolean(),
72864
- error: string().optional()
72865
- }), { auth: "admin" }), method(_void(), array(ProviderListEntrySchema).readonly()), method(object({
72866
- providerId: string(),
72867
- /**
72868
- * The location this config is an UNSAVED edit of, when there is one.
72869
- *
72870
- * `listLocations` replaces every declared secret with the redaction
72871
- * sentinel, so the edit modal's form state holds the sentinel for any
72872
- * credential the operator did not retype — and posting that here
72873
- * without a way to resolve it makes the provider try to authenticate
72874
- * as `__camstack_redacted__` and report the operator's own working
72875
- * password as wrong. Given this id, the orchestrator restores each
72876
- * sentinel from the stored config (same rule as `upsertLocation`)
72877
- * before dispatching. Omitted by the "Add location" wizard, where
72878
- * every value was typed just now and nothing is stored yet.
72879
- */
72880
- locationId: string().optional(),
72881
- config: record(string(), unknown())
72882
- }), object({
72883
- ok: boolean(),
72884
- error: string().optional()
72885
- }), { auth: "admin" });
72777
+ }), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(_void(), array(StorageDrainProgressSchema).readonly());
72886
72778
  /** One table of the settings database. */
72887
72779
  var StorageTableSchema = object({
72888
72780
  /** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
@@ -80475,13 +80367,6 @@ Object.freeze({
80475
80367
  access: "delete",
80476
80368
  role: "admin"
80477
80369
  },
80478
- "llm.deleteProfile": {
80479
- capName: "llm",
80480
- capScope: "system",
80481
- addonId: null,
80482
- access: "delete",
80483
- role: "admin"
80484
- },
80485
80370
  "llm.generate": {
80486
80371
  capName: "llm",
80487
80372
  capScope: "system",
@@ -80545,20 +80430,6 @@ Object.freeze({
80545
80430
  access: "view",
80546
80431
  role: "admin"
80547
80432
  },
80548
- "llm.listProfileKinds": {
80549
- capName: "llm",
80550
- capScope: "system",
80551
- addonId: null,
80552
- access: "view",
80553
- role: "admin"
80554
- },
80555
- "llm.listProfiles": {
80556
- capName: "llm",
80557
- capScope: "system",
80558
- addonId: null,
80559
- access: "view",
80560
- role: "admin"
80561
- },
80562
80433
  "llm.listRuntimeNodes": {
80563
80434
  capName: "llm",
80564
80435
  capScope: "system",
@@ -80566,13 +80437,6 @@ Object.freeze({
80566
80437
  access: "view",
80567
80438
  role: "admin"
80568
80439
  },
80569
- "llm.migrateRawSecrets": {
80570
- capName: "llm",
80571
- capScope: "system",
80572
- addonId: null,
80573
- access: "create",
80574
- role: "admin"
80575
- },
80576
80440
  "llm.resolveModelRef": {
80577
80441
  capName: "llm",
80578
80442
  capScope: "system",
@@ -80601,20 +80465,6 @@ Object.freeze({
80601
80465
  access: "create",
80602
80466
  role: "admin"
80603
80467
  },
80604
- "llm.testProfile": {
80605
- capName: "llm",
80606
- capScope: "system",
80607
- addonId: null,
80608
- access: "create",
80609
- role: "admin"
80610
- },
80611
- "llm.upsertProfile": {
80612
- capName: "llm",
80613
- capScope: "system",
80614
- addonId: null,
80615
- access: "create",
80616
- role: "admin"
80617
- },
80618
80468
  "llmRuntime.appleAvailability": {
80619
80469
  capName: "llm-runtime",
80620
80470
  capScope: "system",
@@ -81119,13 +80969,6 @@ Object.freeze({
81119
80969
  access: "create",
81120
80970
  role: "admin"
81121
80971
  },
81122
- "meshNetwork.testConnection": {
81123
- capName: "mesh-network",
81124
- capScope: "system",
81125
- addonId: null,
81126
- access: "create",
81127
- role: "admin"
81128
- },
81129
80972
  "meter.getStatus": {
81130
80973
  capName: "meter",
81131
80974
  capScope: "device",
@@ -81784,13 +81627,6 @@ Object.freeze({
81784
81627
  access: "create",
81785
81628
  role: "admin"
81786
81629
  },
81787
- "notificationOutput.deleteTarget": {
81788
- capName: "notification-output",
81789
- capScope: "system",
81790
- addonId: null,
81791
- access: "delete",
81792
- role: "admin"
81793
- },
81794
81630
  "notificationOutput.discoverTargets": {
81795
81631
  capName: "notification-output",
81796
81632
  capScope: "system",
@@ -81798,13 +81634,6 @@ Object.freeze({
81798
81634
  access: "view",
81799
81635
  role: "admin"
81800
81636
  },
81801
- "notificationOutput.getTarget": {
81802
- capName: "notification-output",
81803
- capScope: "system",
81804
- addonId: null,
81805
- access: "view",
81806
- role: "admin"
81807
- },
81808
81637
  "notificationOutput.listTargetKinds": {
81809
81638
  capName: "notification-output",
81810
81639
  capScope: "system",
@@ -81812,13 +81641,6 @@ Object.freeze({
81812
81641
  access: "view",
81813
81642
  role: "admin"
81814
81643
  },
81815
- "notificationOutput.listTargets": {
81816
- capName: "notification-output",
81817
- capScope: "system",
81818
- addonId: null,
81819
- access: "view",
81820
- role: "admin"
81821
- },
81822
81644
  "notificationOutput.probeTargetConfig": {
81823
81645
  capName: "notification-output",
81824
81646
  capScope: "system",
@@ -81833,13 +81655,6 @@ Object.freeze({
81833
81655
  access: "create",
81834
81656
  role: "admin"
81835
81657
  },
81836
- "notificationOutput.setTargetEnabled": {
81837
- capName: "notification-output",
81838
- capScope: "system",
81839
- addonId: null,
81840
- access: "create",
81841
- role: "admin"
81842
- },
81843
81658
  "notificationOutput.testTarget": {
81844
81659
  capName: "notification-output",
81845
81660
  capScope: "system",
@@ -81847,13 +81662,6 @@ Object.freeze({
81847
81662
  access: "create",
81848
81663
  role: "admin"
81849
81664
  },
81850
- "notificationOutput.upsertTarget": {
81851
- capName: "notification-output",
81852
- capScope: "system",
81853
- addonId: null,
81854
- access: "create",
81855
- role: "admin"
81856
- },
81857
81665
  "notificationRules.activateAlarmProfile": {
81858
81666
  capName: "notification-rules",
81859
81667
  capScope: "system",
@@ -82113,41 +81921,6 @@ Object.freeze({
82113
81921
  access: "view",
82114
81922
  role: "admin"
82115
81923
  },
82116
- "oidcConnections.connectionFormSchema": {
82117
- capName: "oidc-connections",
82118
- capScope: "system",
82119
- addonId: null,
82120
- access: "view",
82121
- role: "admin"
82122
- },
82123
- "oidcConnections.createConnection": {
82124
- capName: "oidc-connections",
82125
- capScope: "system",
82126
- addonId: null,
82127
- access: "create",
82128
- role: "admin"
82129
- },
82130
- "oidcConnections.deleteConnection": {
82131
- capName: "oidc-connections",
82132
- capScope: "system",
82133
- addonId: null,
82134
- access: "delete",
82135
- role: "admin"
82136
- },
82137
- "oidcConnections.listConnections": {
82138
- capName: "oidc-connections",
82139
- capScope: "system",
82140
- addonId: null,
82141
- access: "view",
82142
- role: "admin"
82143
- },
82144
- "oidcConnections.updateConnection": {
82145
- capName: "oidc-connections",
82146
- capScope: "system",
82147
- addonId: null,
82148
- access: "create",
82149
- role: "admin"
82150
- },
82151
81924
  "osd.getStatus": {
82152
81925
  capName: "osd",
82153
81926
  capScope: "device",
@@ -85179,13 +84952,6 @@ Object.freeze({
85179
84952
  access: "delete",
85180
84953
  role: "admin"
85181
84954
  },
85182
- "storage.deleteLocation": {
85183
- capName: "storage",
85184
- capScope: "system",
85185
- addonId: null,
85186
- access: "delete",
85187
- role: "admin"
85188
- },
85189
84955
  "storage.endDownload": {
85190
84956
  capName: "storage",
85191
84957
  capScope: "system",
@@ -85242,13 +85008,6 @@ Object.freeze({
85242
85008
  access: "view",
85243
85009
  role: "admin"
85244
85010
  },
85245
- "storage.listProviders": {
85246
- capName: "storage",
85247
- capScope: "system",
85248
- addonId: null,
85249
- access: "view",
85250
- role: "admin"
85251
- },
85252
85011
  "storage.read": {
85253
85012
  capName: "storage",
85254
85013
  capScope: "system",
@@ -85270,27 +85029,6 @@ Object.freeze({
85270
85029
  access: "view",
85271
85030
  role: "admin"
85272
85031
  },
85273
- "storage.testConfig": {
85274
- capName: "storage",
85275
- capScope: "system",
85276
- addonId: null,
85277
- access: "view",
85278
- role: "admin"
85279
- },
85280
- "storage.testLocation": {
85281
- capName: "storage",
85282
- capScope: "system",
85283
- addonId: null,
85284
- access: "view",
85285
- role: "admin"
85286
- },
85287
- "storage.upsertLocation": {
85288
- capName: "storage",
85289
- capScope: "system",
85290
- addonId: null,
85291
- access: "create",
85292
- role: "admin"
85293
- },
85294
85032
  "storage.write": {
85295
85033
  capName: "storage",
85296
85034
  capScope: "system",
@@ -91843,222 +91581,6 @@ var GoogleBrokerRegistry = class {
91843
91581
  }
91844
91582
  };
91845
91583
  //#endregion
91846
- //#region src/google-settings-copy.ts
91847
- /**
91848
- * Operator-facing setup copy for Connectivity → Calendars / Email.
91849
- * Keep Connect as a same-origin relative link so the admin session cookie
91850
- * rides along (an absolute Public URL from a LAN admin tab drops the cookie).
91851
- * Root-relative hrefs must survive `sanitizeInfoHtml` in ui-library.
91852
- */
91853
- /** Enable APIs library in Google Cloud Console. */
91854
- var GOOGLE_CONSOLE_APIS_URL = "https://console.cloud.google.com/apis/library";
91855
- /** Create / manage OAuth Web clients. */
91856
- var GOOGLE_CONSOLE_CREDENTIALS_URL = "https://console.cloud.google.com/apis/credentials";
91857
- function redirectUriDisplay(publicOrigin) {
91858
- if (publicOrigin === null || publicOrigin.length === 0) return `<public-hub>${OAUTH_CALLBACK_SUFFIX}`;
91859
- return `${publicOrigin.replace(/\/$/, "")}${OAUTH_CALLBACK_SUFFIX}`;
91860
- }
91861
- function consoleLinksHtml$1() {
91862
- return [
91863
- `<a href="${GOOGLE_CONSOLE_APIS_URL}">API library</a>`,
91864
- ` · `,
91865
- `<a href="${GOOGLE_CONSOLE_CREDENTIALS_URL}">Credentials</a>`
91866
- ].join("");
91867
- }
91868
- function introHtml(cap, publicOrigin) {
91869
- const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
91870
- const console = consoleLinksHtml$1();
91871
- if (cap === "smtp-provider") return [
91872
- "<ol>",
91873
- `<li>Open Google Cloud Console (${console}) and enable the <strong>Gmail API</strong> (and Calendar API if you also use Calendars).</li>`,
91874
- "<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
91875
- `<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
91876
- "<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
91877
- `<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
91878
- "<li>Set From address (connected account or a verified send-as). Turn this integration off with the page <strong>Enable</strong> toggle when you do not want Gmail send — Calendar can stay connected.</li>",
91879
- "</ol>"
91880
- ].join("");
91881
- if (cap === "calendar-source") return [
91882
- "<ol>",
91883
- `<li>Open Google Cloud Console (${console}) and enable the <strong>Google Calendar API</strong> (and Gmail API if you also use Email).</li>`,
91884
- "<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
91885
- `<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
91886
- "<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
91887
- `<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
91888
- "<li>Optionally restrict which calendars are exposed with the filter below.</li>",
91889
- "</ol>"
91890
- ].join("");
91891
- return [
91892
- "<ol>",
91893
- `<li>Open Google Cloud Console (${console}) and enable <strong>Google Calendar API</strong> and <strong>Gmail API</strong>.</li>`,
91894
- "<li>Create a <strong>Web application</strong> OAuth client under Credentials.</li>",
91895
- `<li>Register redirect URI: <code>${redirect}</code> (Network → Public endpoint).</li>`,
91896
- `<li>Paste Client ID / secret, Save, then <a href="${OAUTH_START_PATH}">Connect Google</a>.</li>`,
91897
- "<li>Calendars and Email share one Google account; use each page’s <strong>Enable</strong> toggle to turn a capability off without revoking OAuth.</li>",
91898
- "</ol>"
91899
- ].join("");
91900
- }
91901
- function connectHtml(cap, publicOrigin) {
91902
- const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
91903
- if (cap === "smtp-provider") return [
91904
- `After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
91905
- "Connect requests <code>gmail.send</code> (and Calendar read for the Calendars page). ",
91906
- `Google must list exactly: <code>${redirect}</code>. `,
91907
- "If an older Connect predates Gmail send, revoke CamStack in Google Account → Security and Connect again. ",
91908
- `Console: ${consoleLinksHtml$1()}.`
91909
- ].join("");
91910
- if (cap === "calendar-source") return [
91911
- `After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
91912
- "Connect requests <code>calendar.readonly</code> (and Gmail send for the Email page). ",
91913
- `Google must list exactly: <code>${redirect}</code>. `,
91914
- `Console: ${consoleLinksHtml$1()}.`
91915
- ].join("");
91916
- return [
91917
- `After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a>. `,
91918
- `Redirect URI registered in Google Cloud must be <code>${redirect}</code>. `,
91919
- `Console: ${consoleLinksHtml$1()}.`
91920
- ].join("");
91921
- }
91922
- function escapeHtml$1(s) {
91923
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
91924
- }
91925
- //#endregion
91926
- //#region src/google-broker-settings-schema.ts
91927
- /**
91928
- * Per-kind broker creation/edit form for kind=`google`.
91929
- * Account linking (Sign in) is driven by the kind's `connectPath`
91930
- * on the instances page — not a hard-coded Connect link in this form.
91931
- */
91932
- function consoleLinksHtml() {
91933
- return [
91934
- `<a href="${GOOGLE_CONSOLE_APIS_URL}">API library</a>`,
91935
- ` · `,
91936
- `<a href="${GOOGLE_CONSOLE_CREDENTIALS_URL}">Credentials</a>`
91937
- ].join("");
91938
- }
91939
- /** Setup steps shown on Add / Edit — includes Audience / Test users. */
91940
- function googleBrokerSetupHtml(publicOrigin) {
91941
- const redirect = escapeHtml(redirectUriDisplay(publicOrigin));
91942
- return [
91943
- "<ol>",
91944
- `<li>Open Google Cloud Console (${consoleLinksHtml()}). Create a <strong>new project</strong> (or pick an existing one) from the project picker at the top.</li>`,
91945
- "<li>In that project, enable <strong>Google Calendar API</strong> and/or <strong>Gmail API</strong> (API library).</li>",
91946
- "<li>Open <strong>Google Auth Platform → Audience</strong> (or APIs &amp; Services → OAuth consent screen → <strong>Audience</strong>). User type <strong>External</strong> + publishing status <strong>Testing</strong> is fine for a personal hub. Under <strong>Test users</strong>, add the Google account(s) that will Sign in — otherwise Google returns <code>403: access_denied</code>. (If you only see Branding / Data Access, open the <strong>Audience</strong> tab in the left sidebar of Google Auth Platform.) Publishing / verification is optional for a private hub.</li>",
91947
- "<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
91948
- `<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
91949
- "<li>Paste Client ID and Client secret below. <strong>Test connection</strong> checks those with Google (not the account yet).</li>",
91950
- "<li>Add the broker — the hub then opens Google sign-in in a popup to link the account (Calendar + Gmail). Use <strong>Sign in</strong> on the row if you skip or cancel.</li>",
91951
- "</ol>"
91952
- ].join("");
91953
- }
91954
- function buildGoogleBrokerSettingsSchema(publicOrigin) {
91955
- return { sections: [
91956
- {
91957
- id: "setup-intro",
91958
- title: "Setup",
91959
- titleKey: "google-services:googleBrokerSettings.s_setup-intro.title",
91960
- description: "Google Cloud Console — register the hub redirect before Add / Sign in.",
91961
- descriptionKey: "google-services:googleBrokerSettings.s_setup-intro.description",
91962
- columns: 1,
91963
- fields: [{
91964
- type: "info",
91965
- key: "_setupSteps",
91966
- label: "Steps",
91967
- labelKey: "google-services:googleBrokerSettings.s_setup-intro._setupSteps.label",
91968
- format: "html",
91969
- content: googleBrokerSetupHtml(publicOrigin)
91970
- }]
91971
- },
91972
- {
91973
- id: "google-oauth-client",
91974
- title: "Google OAuth client",
91975
- titleKey: "google-services:googleBrokerSettings.s_google-oauth-client.title",
91976
- description: "Web application client from Google Cloud Console. The same Cloud project can be reused across Google brokers.",
91977
- descriptionKey: "google-services:googleBrokerSettings.s_google-oauth-client.description",
91978
- columns: 1,
91979
- fields: [{
91980
- type: "text",
91981
- key: "clientId",
91982
- label: "Client ID",
91983
- labelKey: "google-services:googleBrokerSettings.s_google-oauth-client.clientId.label"
91984
- }, {
91985
- type: "password",
91986
- key: "clientSecret",
91987
- label: "Client secret",
91988
- labelKey: "google-services:googleBrokerSettings.s_google-oauth-client.clientSecret.label",
91989
- showToggle: true
91990
- }]
91991
- },
91992
- {
91993
- id: "gmail-send",
91994
- title: "Gmail send",
91995
- titleKey: "google-services:googleBrokerSettings.s_gmail-send.title",
91996
- description: "From must be this connected account or a verified send-as. Disable Email on Connectivity to turn Gmail off without removing the broker.",
91997
- descriptionKey: "google-services:googleBrokerSettings.s_gmail-send.description",
91998
- columns: 1,
91999
- fields: [{
92000
- type: "text",
92001
- key: "fromAddress",
92002
- label: "From address",
92003
- labelKey: "google-services:googleBrokerSettings.s_gmail-send.fromAddress.label",
92004
- description: "Defaults to the connected Google account email when empty.",
92005
- descriptionKey: "google-services:googleBrokerSettings.s_gmail-send.fromAddress.description"
92006
- }, {
92007
- type: "text",
92008
- key: "fromName",
92009
- label: "From display name (optional)",
92010
- labelKey: "google-services:googleBrokerSettings.s_gmail-send.fromName.label"
92011
- }]
92012
- }
92013
- ] };
92014
- }
92015
- /** Connectivity Calendars / Email pages — the calendar import picker is on each broker. */
92016
- function buildGoogleFeatureSettingsSchema(cap, publicOrigin) {
92017
- const redirect = escapeHtml(redirectUriDisplay(publicOrigin));
92018
- if (cap === "calendar-source") return { sections: [{
92019
- id: "setup-intro",
92020
- title: "Google brokers",
92021
- titleKey: "google-services:googleFeatureSettings.s_setup-intro.title",
92022
- columns: 1,
92023
- fields: [{
92024
- type: "info",
92025
- key: "_setupSteps",
92026
- label: "Setup",
92027
- labelKey: "google-services:googleFeatureSettings.s_setup-intro._setupSteps.label",
92028
- format: "html",
92029
- content: [
92030
- "<p>Link a Google account under Connectivity → <strong>Brokers</strong> ",
92031
- "(Client ID / secret + Sign in), then add a calendar under Connectivity → <strong>Calendars</strong>. ",
92032
- `OAuth redirect URI: <code>${redirect}</code>.</p>`
92033
- ].join("")
92034
- }]
92035
- }] };
92036
- return { sections: [{
92037
- id: "setup-intro",
92038
- title: cap === "smtp-provider" ? "Gmail send uses Google brokers" : "Google brokers",
92039
- columns: 1,
92040
- fields: [{
92041
- type: "info",
92042
- key: "_setupSteps",
92043
- label: "Setup",
92044
- labelKey: "google-services:googleFeatureSettings._setupSteps.label",
92045
- format: "html",
92046
- content: cap === "smtp-provider" ? [
92047
- "<p>Add or edit a <strong>Google</strong> broker under Connectivity → <strong>Brokers</strong> ",
92048
- "(Client ID / secret + Sign in). From address and send-as live on that broker. ",
92049
- `OAuth redirect URI: <code>${redirect}</code>.</p>`
92050
- ].join("") : [
92051
- "<p>Add or edit a <strong>Google</strong> broker under Connectivity → <strong>Brokers</strong> ",
92052
- "(Client ID / secret + Sign in). ",
92053
- `OAuth redirect URI: <code>${redirect}</code>.</p>`
92054
- ].join("")
92055
- }]
92056
- }] };
92057
- }
92058
- function escapeHtml(s) {
92059
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
92060
- }
92061
- //#endregion
92062
91584
  //#region src/google-calendar-source.ts
92063
91585
  function parseGoogleInstant(value) {
92064
91586
  const ms = Date.parse(value);
@@ -92579,6 +92101,179 @@ function buildGoogleCalendarInstances(records, deps) {
92579
92101
  });
92580
92102
  }
92581
92103
  //#endregion
92104
+ //#region src/google-settings-copy.ts
92105
+ /**
92106
+ * Operator-facing setup copy for Connectivity → Calendars / Email.
92107
+ * Keep Connect as a same-origin relative link so the admin session cookie
92108
+ * rides along (an absolute Public URL from a LAN admin tab drops the cookie).
92109
+ * Root-relative hrefs must survive `sanitizeInfoHtml` in ui-library.
92110
+ */
92111
+ /** Enable APIs library in Google Cloud Console. */
92112
+ var GOOGLE_CONSOLE_APIS_URL = "https://console.cloud.google.com/apis/library";
92113
+ /** Create / manage OAuth Web clients. */
92114
+ var GOOGLE_CONSOLE_CREDENTIALS_URL = "https://console.cloud.google.com/apis/credentials";
92115
+ function redirectUriDisplay(publicOrigin) {
92116
+ if (publicOrigin === null || publicOrigin.length === 0) return `<public-hub>${OAUTH_CALLBACK_SUFFIX}`;
92117
+ return `${publicOrigin.replace(/\/$/, "")}${OAUTH_CALLBACK_SUFFIX}`;
92118
+ }
92119
+ function consoleLinksHtml$1() {
92120
+ return [
92121
+ `<a href="${GOOGLE_CONSOLE_APIS_URL}">API library</a>`,
92122
+ ` · `,
92123
+ `<a href="${GOOGLE_CONSOLE_CREDENTIALS_URL}">Credentials</a>`
92124
+ ].join("");
92125
+ }
92126
+ function introHtml(cap, publicOrigin) {
92127
+ const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
92128
+ const console = consoleLinksHtml$1();
92129
+ if (cap === "smtp-provider") return [
92130
+ "<ol>",
92131
+ `<li>Open Google Cloud Console (${console}) and enable the <strong>Gmail API</strong> (and Calendar API if you also use Calendars).</li>`,
92132
+ "<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
92133
+ `<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
92134
+ "<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
92135
+ `<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
92136
+ "<li>Set From address (connected account or a verified send-as). Turn this integration off with the page <strong>Enable</strong> toggle when you do not want Gmail send — Calendar can stay connected.</li>",
92137
+ "</ol>"
92138
+ ].join("");
92139
+ if (cap === "calendar-source") return [
92140
+ "<ol>",
92141
+ `<li>Open Google Cloud Console (${console}) and enable the <strong>Google Calendar API</strong> (and Gmail API if you also use Email).</li>`,
92142
+ "<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
92143
+ `<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
92144
+ "<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
92145
+ `<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
92146
+ "<li>Optionally restrict which calendars are exposed with the filter below.</li>",
92147
+ "</ol>"
92148
+ ].join("");
92149
+ return [
92150
+ "<ol>",
92151
+ `<li>Open Google Cloud Console (${console}) and enable <strong>Google Calendar API</strong> and <strong>Gmail API</strong>.</li>`,
92152
+ "<li>Create a <strong>Web application</strong> OAuth client under Credentials.</li>",
92153
+ `<li>Register redirect URI: <code>${redirect}</code> (Network → Public endpoint).</li>`,
92154
+ `<li>Paste Client ID / secret, Save, then <a href="${OAUTH_START_PATH}">Connect Google</a>.</li>`,
92155
+ "<li>Calendars and Email share one Google account; use each page’s <strong>Enable</strong> toggle to turn a capability off without revoking OAuth.</li>",
92156
+ "</ol>"
92157
+ ].join("");
92158
+ }
92159
+ function connectHtml(cap, publicOrigin) {
92160
+ const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
92161
+ if (cap === "smtp-provider") return [
92162
+ `After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
92163
+ "Connect requests <code>gmail.send</code> (and Calendar read for the Calendars page). ",
92164
+ `Google must list exactly: <code>${redirect}</code>. `,
92165
+ "If an older Connect predates Gmail send, revoke CamStack in Google Account → Security and Connect again. ",
92166
+ `Console: ${consoleLinksHtml$1()}.`
92167
+ ].join("");
92168
+ if (cap === "calendar-source") return [
92169
+ `After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
92170
+ "Connect requests <code>calendar.readonly</code> (and Gmail send for the Email page). ",
92171
+ `Google must list exactly: <code>${redirect}</code>. `,
92172
+ `Console: ${consoleLinksHtml$1()}.`
92173
+ ].join("");
92174
+ return [
92175
+ `After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a>. `,
92176
+ `Redirect URI registered in Google Cloud must be <code>${redirect}</code>. `,
92177
+ `Console: ${consoleLinksHtml$1()}.`
92178
+ ].join("");
92179
+ }
92180
+ function escapeHtml$1(s) {
92181
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
92182
+ }
92183
+ //#endregion
92184
+ //#region src/google-broker-settings-schema.ts
92185
+ /**
92186
+ * Per-kind broker creation/edit form for kind=`google`.
92187
+ * Account linking (Sign in) is driven by the kind's `connectPath`
92188
+ * on the instances page — not a hard-coded Connect link in this form.
92189
+ */
92190
+ function consoleLinksHtml() {
92191
+ return [
92192
+ `<a href="${GOOGLE_CONSOLE_APIS_URL}">API library</a>`,
92193
+ ` · `,
92194
+ `<a href="${GOOGLE_CONSOLE_CREDENTIALS_URL}">Credentials</a>`
92195
+ ].join("");
92196
+ }
92197
+ /** Setup steps shown on Add / Edit — includes Audience / Test users. */
92198
+ function googleBrokerSetupHtml(publicOrigin) {
92199
+ const redirect = escapeHtml(redirectUriDisplay(publicOrigin));
92200
+ return [
92201
+ "<ol>",
92202
+ `<li>Open Google Cloud Console (${consoleLinksHtml()}). Create a <strong>new project</strong> (or pick an existing one) from the project picker at the top.</li>`,
92203
+ "<li>In that project, enable <strong>Google Calendar API</strong> and/or <strong>Gmail API</strong> (API library).</li>",
92204
+ "<li>Open <strong>Google Auth Platform → Audience</strong> (or APIs &amp; Services → OAuth consent screen → <strong>Audience</strong>). User type <strong>External</strong> + publishing status <strong>Testing</strong> is fine for a personal hub. Under <strong>Test users</strong>, add the Google account(s) that will Sign in — otherwise Google returns <code>403: access_denied</code>. (If you only see Branding / Data Access, open the <strong>Audience</strong> tab in the left sidebar of Google Auth Platform.) Publishing / verification is optional for a private hub.</li>",
92205
+ "<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
92206
+ `<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
92207
+ "<li>Paste Client ID and Client secret below. <strong>Test connection</strong> checks those with Google (not the account yet).</li>",
92208
+ "<li>Add the broker — the hub then opens Google sign-in in a popup to link the account (Calendar + Gmail). Use <strong>Sign in</strong> on the row if you skip or cancel.</li>",
92209
+ "</ol>"
92210
+ ].join("");
92211
+ }
92212
+ function buildGoogleBrokerSettingsSchema(publicOrigin) {
92213
+ return { sections: [
92214
+ {
92215
+ id: "setup-intro",
92216
+ title: "Setup",
92217
+ titleKey: "google-services:googleBrokerSettings.s_setup-intro.title",
92218
+ description: "Google Cloud Console — register the hub redirect before Add / Sign in.",
92219
+ descriptionKey: "google-services:googleBrokerSettings.s_setup-intro.description",
92220
+ columns: 1,
92221
+ fields: [{
92222
+ type: "info",
92223
+ key: "_setupSteps",
92224
+ label: "Steps",
92225
+ labelKey: "google-services:googleBrokerSettings.s_setup-intro._setupSteps.label",
92226
+ format: "html",
92227
+ content: googleBrokerSetupHtml(publicOrigin)
92228
+ }]
92229
+ },
92230
+ {
92231
+ id: "google-oauth-client",
92232
+ title: "Google OAuth client",
92233
+ titleKey: "google-services:googleBrokerSettings.s_google-oauth-client.title",
92234
+ description: "Web application client from Google Cloud Console. The same Cloud project can be reused across Google brokers.",
92235
+ descriptionKey: "google-services:googleBrokerSettings.s_google-oauth-client.description",
92236
+ columns: 1,
92237
+ fields: [{
92238
+ type: "text",
92239
+ key: "clientId",
92240
+ label: "Client ID",
92241
+ labelKey: "google-services:googleBrokerSettings.s_google-oauth-client.clientId.label"
92242
+ }, {
92243
+ type: "password",
92244
+ key: "clientSecret",
92245
+ label: "Client secret",
92246
+ labelKey: "google-services:googleBrokerSettings.s_google-oauth-client.clientSecret.label",
92247
+ showToggle: true
92248
+ }]
92249
+ },
92250
+ {
92251
+ id: "gmail-send",
92252
+ title: "Gmail send",
92253
+ titleKey: "google-services:googleBrokerSettings.s_gmail-send.title",
92254
+ description: "From must be this connected account or a verified send-as. Disable Email on Connectivity to turn Gmail off without removing the broker.",
92255
+ descriptionKey: "google-services:googleBrokerSettings.s_gmail-send.description",
92256
+ columns: 1,
92257
+ fields: [{
92258
+ type: "text",
92259
+ key: "fromAddress",
92260
+ label: "From address",
92261
+ labelKey: "google-services:googleBrokerSettings.s_gmail-send.fromAddress.label",
92262
+ description: "Defaults to the connected Google account email when empty.",
92263
+ descriptionKey: "google-services:googleBrokerSettings.s_gmail-send.fromAddress.description"
92264
+ }, {
92265
+ type: "text",
92266
+ key: "fromName",
92267
+ label: "From display name (optional)",
92268
+ labelKey: "google-services:googleBrokerSettings.s_gmail-send.fromName.label"
92269
+ }]
92270
+ }
92271
+ ] };
92272
+ }
92273
+ function escapeHtml(s) {
92274
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
92275
+ }
92276
+ //#endregion
92582
92277
  //#region src/google-instances.ts
92583
92278
  /**
92584
92279
  * The Google accounts as `integration-instances` (planning#408 P3): one instance per broker
@@ -93865,21 +93560,6 @@ var GoogleServicesAddon = class extends BaseAddon {
93865
93560
  this.publicOrigin = null;
93866
93561
  }
93867
93562
  }
93868
- /**
93869
- * Connectivity Calendars / Email: point at Brokers (no duplicate OAuth fields).
93870
- * Addon page without cap: same pointer + note.
93871
- */
93872
- globalSettingsSchema(cap) {
93873
- const scoped = asSettingsCap(cap);
93874
- return this.schema(buildGoogleFeatureSettingsSchema(scoped, this.publicOrigin));
93875
- }
93876
- async getGlobalSettings(overlay, cap, nodeId) {
93877
- await this.refreshPublicOrigin();
93878
- return super.getGlobalSettings(overlay, cap, nodeId);
93879
- }
93880
93563
  };
93881
- function asSettingsCap(cap) {
93882
- if (cap === "calendar-source" || cap === "smtp-provider") return cap;
93883
- }
93884
93564
  //#endregion
93885
- export { GOOGLE_OAUTH_SCOPES as C, GoogleServicesAddon, GoogleServicesAddon as default, GOOGLE_GMAIL_SEND_SCOPE as S, OAUTH_START_PATH as T, GoogleBrokerRegistry as _, refreshAccessToken as a, DEFAULT_GOOGLE_CONFIG as b, selectGmailAccount as c, mapGoogleEvent as d, GOOGLE_CONSOLE_APIS_URL as f, redirectUriDisplay as g, introHtml as h, needsRefresh as i, createGoogleCalendarApi as l, connectHtml as m, buildAuthorizeUrl as n, buildRawMime as o, GOOGLE_CONSOLE_CREDENTIALS_URL as p, exchangeCode as r, createGmailSmtpProvider as s, applyTokenResponse as t, createGoogleCalendarSource as u, parseStampedCalendarId as v, GoogleServicesConfigSchema as w, GOOGLE_BROKER_KIND as x, stampCalendarId as y };
93565
+ export { GOOGLE_OAUTH_SCOPES as C, GoogleServicesAddon, GoogleServicesAddon as default, GOOGLE_GMAIL_SEND_SCOPE as S, OAUTH_START_PATH as T, GoogleBrokerRegistry as _, redirectUriDisplay as a, DEFAULT_GOOGLE_CONFIG as b, exchangeCode as c, buildRawMime as d, createGmailSmtpProvider as f, mapGoogleEvent as g, createGoogleCalendarSource as h, introHtml as i, needsRefresh as l, createGoogleCalendarApi as m, GOOGLE_CONSOLE_CREDENTIALS_URL as n, applyTokenResponse as o, selectGmailAccount as p, connectHtml as r, buildAuthorizeUrl as s, GOOGLE_CONSOLE_APIS_URL as t, refreshAccessToken as u, parseStampedCalendarId as v, GoogleServicesConfigSchema as w, GOOGLE_BROKER_KIND as x, stampCalendarId as y };