camstack 1.2.190 → 1.2.192

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -37,7 +37,7 @@ async function runServe(args) {
37
37
  ...typeof values.data === "string" ? { data: values.data } : {}
38
38
  };
39
39
  Object.assign(process.env, buildServeEnv(opts));
40
- await import("./launcher-ILGFB3AQ.js");
40
+ await import("./launcher-PJJ7PTWL.js");
41
41
  }
42
42
 
43
43
  // src/commands/agent.ts
@@ -82,7 +82,7 @@ async function runAgent(args) {
82
82
  ...typeof values.port === "string" ? { port: values.port } : {}
83
83
  };
84
84
  Object.assign(process.env, buildAgentEnv(opts));
85
- await import("./launcher-ILGFB3AQ.js");
85
+ await import("./launcher-PJJ7PTWL.js");
86
86
  }
87
87
 
88
88
  // src/commands/setup.ts
@@ -14773,7 +14773,7 @@ function date4(params) {
14773
14773
  // ../../node_modules/zod/v4/classic/external.js
14774
14774
  config(en_default());
14775
14775
 
14776
- // ../types/dist/sleep-BxjU_fJM.mjs
14776
+ // ../types/dist/sleep-yKL5gfrH.mjs
14777
14777
  var AUDIO_CHUNK_FORMATS = [
14778
14778
  "f32le",
14779
14779
  "pcmu",
@@ -14968,6 +14968,7 @@ var WELL_KNOWN_TABS = [
14968
14968
  ];
14969
14969
  var WELL_KNOWN_TAB_MAP = Object.fromEntries(WELL_KNOWN_TABS.map((t) => [t.id, t]));
14970
14970
  var SECRET_RETRY_MAX_MS = 5 * 6e4;
14971
+ var SHARE_VIEW_KINDS = ["grid-view", "events-view"];
14971
14972
  var PEER_BYTES_CHUNK_BYTES = 256 * 1024;
14972
14973
  var PeerBytesTicketSchema = external_exports.object({
14973
14974
  /** `http://127.0.0.1:<port>/<token>`. One `GET` takes it. */
@@ -18452,6 +18453,204 @@ var ConvertResultSchema = external_exports.object({
18452
18453
  entry: ModelCatalogEntrySchema,
18453
18454
  artifacts: external_exports.array(ConvertArtifactSchema).readonly()
18454
18455
  });
18456
+ var MethodAccessSchema = external_exports.enum([
18457
+ "view",
18458
+ "create",
18459
+ "delete"
18460
+ ]);
18461
+ var AllowedProviderSchema = external_exports.union([external_exports.literal("*"), external_exports.array(external_exports.string())]);
18462
+ var AllowedDevicesSchema = external_exports.record(external_exports.string(), external_exports.union([external_exports.literal("*"), external_exports.array(external_exports.string())]));
18463
+ var CapScopeSchema = external_exports.enum(["device", "system"]);
18464
+ var DeviceSelectorSchema = external_exports.discriminatedUnion("kind", [
18465
+ external_exports.object({ kind: external_exports.literal("all") }),
18466
+ external_exports.object({
18467
+ kind: external_exports.literal("ids"),
18468
+ ids: external_exports.array(external_exports.number().int()).min(1)
18469
+ }),
18470
+ external_exports.object({
18471
+ kind: external_exports.literal("types"),
18472
+ types: external_exports.array(external_exports.enum(DeviceType)).min(1)
18473
+ }),
18474
+ external_exports.object({
18475
+ kind: external_exports.literal("locations"),
18476
+ locations: external_exports.array(external_exports.string().min(1)).min(1)
18477
+ })
18478
+ ]);
18479
+ var DeviceTokenScopeSchema = external_exports.object({
18480
+ type: external_exports.literal("device"),
18481
+ /** The device SET this grant covers — resolved against the live fleet. */
18482
+ selector: DeviceSelectorSchema,
18483
+ access: external_exports.array(MethodAccessSchema).min(1),
18484
+ /**
18485
+ * Whether a grant on a PARENT device transparently covers its accessory
18486
+ * CHILDREN (siren / floodlight / PIR) via the persisted-parentage walk.
18487
+ * Direction is parent → children ONLY.
18488
+ *
18489
+ * Absent → the matcher DERIVES it from the access flavour: `view`
18490
+ * inherits (a camera viewer sees the camera's accessories), `create` /
18491
+ * `delete` do NOT (actuating/removing a child is an explicit act the
18492
+ * operator must grant on the child, not inherit from the parent). Set it
18493
+ * explicitly to override that default per grant.
18494
+ */
18495
+ includeLinked: external_exports.boolean().optional()
18496
+ });
18497
+ function migrateLegacyTokenScope(raw) {
18498
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
18499
+ if (Reflect.get(raw, "type") !== "device") return raw;
18500
+ if (Reflect.get(raw, "selector") !== void 0) return raw;
18501
+ const targets = Reflect.get(raw, "targets");
18502
+ if (!Array.isArray(targets)) return raw;
18503
+ return {
18504
+ type: "device",
18505
+ selector: {
18506
+ kind: "ids",
18507
+ ids: targets.map((t) => typeof t === "string" ? Number(t) : t).filter((n) => typeof n === "number" && Number.isInteger(n))
18508
+ },
18509
+ access: Reflect.get(raw, "access")
18510
+ };
18511
+ }
18512
+ var TokenScopeSchema = external_exports.preprocess(migrateLegacyTokenScope, external_exports.discriminatedUnion("type", [
18513
+ external_exports.object({
18514
+ type: external_exports.literal("category"),
18515
+ target: CapScopeSchema,
18516
+ access: external_exports.array(MethodAccessSchema).min(1)
18517
+ }),
18518
+ external_exports.object({
18519
+ type: external_exports.literal("capability"),
18520
+ target: external_exports.string(),
18521
+ access: external_exports.array(MethodAccessSchema).min(1)
18522
+ }),
18523
+ external_exports.object({
18524
+ type: external_exports.literal("addon"),
18525
+ target: external_exports.string(),
18526
+ access: external_exports.array(MethodAccessSchema).min(1)
18527
+ }),
18528
+ DeviceTokenScopeSchema
18529
+ ]));
18530
+ var UserRecordSchema = external_exports.object({
18531
+ id: external_exports.string(),
18532
+ username: external_exports.string(),
18533
+ passwordHash: external_exports.string(),
18534
+ /**
18535
+ * Admin bypass. When true, the middleware skips the scope-access
18536
+ * check entirely. There is no other axis of privilege; the legacy
18537
+ * role enum collapsed onto this boolean in v2.
18538
+ */
18539
+ isAdmin: external_exports.boolean().default(false),
18540
+ allowedProviders: AllowedProviderSchema,
18541
+ allowedDevices: AllowedDevicesSchema,
18542
+ /**
18543
+ * Scopes granted to this user. Admins bypass; their `scopes` is
18544
+ * ignored. Non-admins without scopes are locked out of every
18545
+ * protected call.
18546
+ */
18547
+ scopes: external_exports.array(TokenScopeSchema).default([]),
18548
+ createdAt: external_exports.number(),
18549
+ updatedAt: external_exports.number()
18550
+ });
18551
+ var ApiKeyRecordSchema = external_exports.object({
18552
+ id: external_exports.string(),
18553
+ label: external_exports.string(),
18554
+ isAdmin: external_exports.boolean().default(false),
18555
+ allowedProviders: AllowedProviderSchema,
18556
+ allowedDevices: AllowedDevicesSchema,
18557
+ tokenHash: external_exports.string(),
18558
+ tokenPrefix: external_exports.string(),
18559
+ createdAt: external_exports.number(),
18560
+ lastUsedAt: external_exports.number().optional()
18561
+ });
18562
+ var ScopedTokenSchema = external_exports.object({
18563
+ id: external_exports.string(),
18564
+ userId: external_exports.string(),
18565
+ name: external_exports.string(),
18566
+ tokenHash: external_exports.string(),
18567
+ tokenPrefix: external_exports.string(),
18568
+ scopes: external_exports.array(TokenScopeSchema),
18569
+ expiresAt: external_exports.number().nullish(),
18570
+ lastUsedAt: external_exports.number().nullish(),
18571
+ createdAt: external_exports.number()
18572
+ });
18573
+ var ShareViewGrantSchema = external_exports.object({
18574
+ kind: external_exports.enum(SHARE_VIEW_KINDS),
18575
+ deviceIds: external_exports.array(external_exports.number().int().nonnegative()).min(1).max(64),
18576
+ /** Talk-back, opt-in at mint time; absent means off. */
18577
+ talk: external_exports.boolean().optional()
18578
+ });
18579
+ var ShareViewScopeSchema = external_exports.object({
18580
+ type: external_exports.literal("share-view"),
18581
+ grant: ShareViewGrantSchema
18582
+ });
18583
+ var AddonRoutesScopeSchema = external_exports.object({
18584
+ type: external_exports.literal("addon-routes"),
18585
+ access: external_exports.array(MethodAccessSchema).min(1)
18586
+ });
18587
+ var PreferencesSelfScopeSchema = external_exports.object({ type: external_exports.literal("preferences-self") });
18588
+ var CredentialScopeSchema = external_exports.union([
18589
+ external_exports.literal("*"),
18590
+ ShareViewScopeSchema,
18591
+ AddonRoutesScopeSchema,
18592
+ PreferencesSelfScopeSchema,
18593
+ TokenScopeSchema
18594
+ ]);
18595
+ var CREDENTIAL_TOKEN_KIND = "credential";
18596
+ var CredentialTokenClaimsSchema = external_exports.object({
18597
+ kind: external_exports.literal(CREDENTIAL_TOKEN_KIND),
18598
+ sub: external_exports.string().min(1),
18599
+ jti: external_exports.string().min(16),
18600
+ scopes: external_exports.array(CredentialScopeSchema).min(1)
18601
+ });
18602
+ var PREFERENCES_NAMESPACE_PATTERN = /^[a-z][a-z0-9.-]{0,63}$/;
18603
+ var PREFERENCES_MAX_VALUE_BYTES = 256 * 1024;
18604
+ var PreferenceNamespaceSchema = external_exports.string().regex(PREFERENCES_NAMESPACE_PATTERN);
18605
+ var PreferenceValueSchema = external_exports.record(external_exports.string(), external_exports.unknown());
18606
+ var PreferenceDeviceIdSchema = external_exports.string().min(1).max(64);
18607
+ var PreferenceRowSchema = external_exports.object({
18608
+ namespace: PreferenceNamespaceSchema,
18609
+ value: PreferenceValueSchema,
18610
+ /** Starts at 1, +1 on every write of this namespace. A delete ends the row and its count. */
18611
+ revision: external_exports.number().int().positive(),
18612
+ updatedAt: external_exports.number().int(),
18613
+ /** The client id the last writer sent; `null` when it sent none. */
18614
+ updatedByDevice: PreferenceDeviceIdSchema.nullable()
18615
+ });
18616
+ var PreferencesGetInputSchema = external_exports.object({
18617
+ /** Absent: every namespace the caller holds. */
18618
+ namespaces: external_exports.array(PreferenceNamespaceSchema).max(32).optional()
18619
+ });
18620
+ var PreferencesGetOutputSchema = external_exports.object({ rows: external_exports.array(PreferenceRowSchema) });
18621
+ var PreferencesPutInputSchema = external_exports.object({
18622
+ namespace: PreferenceNamespaceSchema,
18623
+ value: PreferenceValueSchema,
18624
+ /**
18625
+ * The revision the edit was based on. Absent: last write wins. `0`: the
18626
+ * namespace must not exist yet. Any other value that is not the current
18627
+ * revision answers `conflict` and writes nothing.
18628
+ */
18629
+ baseRevision: external_exports.number().int().nonnegative().optional(),
18630
+ deviceId: PreferenceDeviceIdSchema.optional()
18631
+ });
18632
+ var PreferencesPutOutputSchema = external_exports.discriminatedUnion("status", [external_exports.object({
18633
+ status: external_exports.literal("saved"),
18634
+ row: PreferenceRowSchema
18635
+ }), external_exports.object({
18636
+ status: external_exports.literal("conflict"),
18637
+ current: PreferenceRowSchema.nullable()
18638
+ })]);
18639
+ var PreferencesDeleteInputSchema = external_exports.object({ namespace: PreferenceNamespaceSchema });
18640
+ var PreferencesDeleteOutputSchema = external_exports.object({
18641
+ /** `false` when the namespace did not exist. */
18642
+ deleted: external_exports.boolean()
18643
+ });
18644
+ var PreferencesChangedSinceInputSchema = external_exports.object({
18645
+ /** The revision the client holds per namespace; a namespace it does not list is new to it. */
18646
+ revisionByNamespace: external_exports.record(PreferenceNamespaceSchema, external_exports.number().int().nonnegative()).refine((map2) => Object.keys(map2).length <= 32, { message: `at most 32 namespaces` })
18647
+ });
18648
+ var PreferencesChangedSinceOutputSchema = external_exports.object({
18649
+ /** Every row whose revision differs from the client's, and every row it did not list. */
18650
+ rows: external_exports.array(PreferenceRowSchema),
18651
+ /** Namespaces the client listed that no longer exist. */
18652
+ deleted: external_exports.array(PreferenceNamespaceSchema)
18653
+ });
18455
18654
  var AppFlowPurposeSchema = external_exports.enum(["new-session", "step-up"]);
18456
18655
  var AppPageLangSchema = external_exports.enum(["en", "it"]);
18457
18656
  var APP_FLOW_REFUSAL_MESSAGES = {
@@ -46431,27 +46630,30 @@ var llmRuntimeCapability = {
46431
46630
  })
46432
46631
  }
46433
46632
  };
46434
- var LlmProfileKindSchema = external_exports.enum([
46435
- "openai-compatible",
46436
- "openai",
46437
- "anthropic",
46438
- "google",
46439
- "managed-local",
46440
- "apple-foundation"
46441
- ]);
46633
+ var LLM_PROFILE_KIND_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
46634
+ var LlmProfileKindSchema = external_exports.string().regex(LLM_PROFILE_KIND_PATTERN, "a kind id is lower-case letters, digits and dashes");
46635
+ var LlmModelFeaturesSchema = external_exports.object({
46636
+ vision: external_exports.boolean(),
46637
+ tools: external_exports.boolean(),
46638
+ streaming: external_exports.boolean()
46639
+ });
46640
+ var LlmModelInfoSchema = external_exports.object({
46641
+ id: external_exports.string(),
46642
+ label: external_exports.string().optional(),
46643
+ contextLength: external_exports.number().int().positive().optional(),
46644
+ features: LlmModelFeaturesSchema.partial().optional()
46645
+ });
46646
+ var LlmProviderConfigSchema = external_exports.record(external_exports.string(), external_exports.unknown());
46442
46647
  var LlmProfileSchema = external_exports.object({
46443
46648
  id: external_exports.string(),
46444
46649
  name: external_exports.string(),
46650
+ /** The provider-declared kind (`LlmProfileKindDescriptor.kind`). */
46445
46651
  kind: LlmProfileKindSchema,
46446
46652
  /** Stamped by the provider — keeps the fanned catalog routable. */
46447
46653
  addonId: external_exports.string(),
46448
46654
  enabled: external_exports.boolean(),
46449
46655
  /** Vendor model id, or the managed runtime's loaded model. */
46450
46656
  model: external_exports.string(),
46451
- /** Required for openai-compatible; override for cloud kinds. */
46452
- baseUrl: external_exports.string().optional(),
46453
- /** ConfigUISchema type:'password' — never round-trips (spec §5). */
46454
- apiKey: external_exports.string().optional(),
46455
46657
  /** Vision on/off. A vision call against a `false` profile is REFUSED, never
46456
46658
  * degraded to text — that shipped once and produced a confident answer to a
46457
46659
  * question about a picture nobody sent. */
@@ -46459,15 +46661,11 @@ var LlmProfileSchema = external_exports.object({
46459
46661
  temperature: external_exports.number().min(0).max(2).optional(),
46460
46662
  /** Nucleus sampling. Every wire we speak has it. */
46461
46663
  topP: external_exports.number().min(0).max(1).optional(),
46462
- /** Top-k sampling. Carried only by the wires that have it — NEITHER OpenAI
46463
- * wire does, and the client drops it there (measured: the request body gets
46464
- * `top_p` and no `top_k`). The profile editor hides the field wherever it
46465
- * would change nothing; `KINDS_WITH_TOP_K` is the single owner of that list. */
46664
+ /** Top-k sampling. Carried only by the wires that have it — a kind offers the
46665
+ * field in its editor only when its descriptor lists it in `profileFields`. */
46466
46666
  topK: external_exports.number().int().positive().optional(),
46467
46667
  maxTokens: external_exports.number().int().positive().optional(),
46468
- /** Prompt context window. Advisory for cloud kinds (they enforce their own);
46469
- * for `managed-local` it is the llama.cpp `--ctx-size` the runtime starts
46470
- * the model with, so it is the one field that changes a PROCESS. */
46668
+ /** Prompt context window. Advisory for cloud kinds (they enforce their own). */
46471
46669
  contextLength: external_exports.number().int().positive().optional(),
46472
46670
  /** Default system prompt. A caller's `system` REPLACES it (never appends —
46473
46671
  * two system prompts fighting is worse than either alone). */
@@ -46493,26 +46691,76 @@ var LlmProfileSchema = external_exports.object({
46493
46691
  * library; the REGISTRY of callable tools is ours and is empty in v1, so a
46494
46692
  * `true` here buys the wiring, not behaviour, until tools are registered. */
46495
46693
  toolsEnabled: external_exports.boolean().default(false),
46496
- extraHeaders: external_exports.record(external_exports.string(), external_exports.string()).optional(),
46497
- /** kind === 'managed-local' only (spec §4). */
46498
- runtime: ManagedRuntimeConfigSchema.optional(),
46499
- /**
46500
- * kind === 'apple-foundation' only: WHERE it runs — the only thing there is
46501
- * to configure (no key, no URL, no download; `model` is `apple-system`).
46502
- * `supportsVision` on such a row is stamped by the provider from the node's
46503
- * reported `imageInput`, never taken from the operator (D62).
46504
- */
46505
- appleFoundation: external_exports.object({ nodeId: external_exports.string() }).optional()
46694
+ /** Everything the kind's provider owns (endpoint, key, node, runtime…). */
46695
+ providerConfig: LlmProviderConfigSchema.default({})
46696
+ });
46697
+ var LlmProfileFieldSchema = external_exports.enum([
46698
+ "temperature",
46699
+ "topP",
46700
+ "topK",
46701
+ "maxTokens",
46702
+ "contextLength",
46703
+ "systemPrompt",
46704
+ "timeoutMs",
46705
+ "connectTimeoutMs",
46706
+ "firstTokenTimeoutMs",
46707
+ "idleTimeoutMs",
46708
+ "retry",
46709
+ "toolsEnabled"
46710
+ ]);
46711
+ var LlmProviderWidgetSchema = external_exports.object({
46712
+ id: external_exports.string(),
46713
+ placement: external_exports.enum(["connection", "model"]),
46714
+ /** `providerConfig` keys this widget must fill before the profile can be saved. */
46715
+ requires: external_exports.array(external_exports.string()).optional()
46506
46716
  });
46507
46717
  var ConfigSchemaPassthrough$3 = external_exports.unknown();
46508
46718
  var LlmProfileKindDescriptorSchema = external_exports.object({
46509
46719
  kind: LlmProfileKindSchema,
46510
46720
  label: external_exports.string(),
46721
+ /** A generic icon name (`cloud`, `plug`, `cpu`) — never a glyph or a logo. */
46511
46722
  icon: external_exports.string(),
46512
46723
  /** Stamped by each provider so the concat-fanned catalog stays routable. */
46513
46724
  addonId: external_exports.string(),
46514
- configSchema: ConfigSchemaPassthrough$3
46725
+ /** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
46726
+ connectionSchema: ConfigSchemaPassthrough$3,
46727
+ /** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
46728
+ advancedSchema: ConfigSchemaPassthrough$3.optional(),
46729
+ /** The kind's defaults; a model from `listModels` may override any of them. */
46730
+ features: LlmModelFeaturesSchema,
46731
+ /** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
46732
+ visionEditable: external_exports.boolean(),
46733
+ /** Where the model list comes from: `listModels`, `staticModels`, or nowhere. */
46734
+ modelCatalog: external_exports.enum([
46735
+ "fetch",
46736
+ "static",
46737
+ "none"
46738
+ ]),
46739
+ staticModels: external_exports.array(LlmModelInfoSchema).optional(),
46740
+ /** The common fields that mean something on this kind's wire. */
46741
+ profileFields: external_exports.array(LlmProfileFieldSchema),
46742
+ providerWidgets: external_exports.array(LlmProviderWidgetSchema).optional()
46743
+ });
46744
+ var LlmListModelsInputSchema = external_exports.object({
46745
+ addonId: external_exports.string(),
46746
+ kind: LlmProfileKindSchema,
46747
+ profileId: external_exports.string().optional(),
46748
+ connection: LlmProviderConfigSchema.optional()
46515
46749
  });
46750
+ var LlmListModelsErrorCodeSchema = external_exports.enum([
46751
+ "auth",
46752
+ "network",
46753
+ "unsupported",
46754
+ "invalid"
46755
+ ]);
46756
+ var LlmListModelsResultSchema = external_exports.discriminatedUnion("ok", [external_exports.object({
46757
+ ok: external_exports.literal(true),
46758
+ models: external_exports.array(LlmModelInfoSchema)
46759
+ }), external_exports.object({
46760
+ ok: external_exports.literal(false),
46761
+ code: LlmListModelsErrorCodeSchema,
46762
+ message: external_exports.string()
46763
+ })]);
46516
46764
  var LlmDefaultSelectorSchema = external_exports.union([external_exports.object({ consumer: external_exports.string() }), external_exports.object({ purpose: external_exports.enum(["text", "vision"]) })]);
46517
46765
  var LlmDefaultSchema = external_exports.object({
46518
46766
  selector: LlmDefaultSelectorSchema,
@@ -46632,8 +46880,17 @@ var llmCapability = {
46632
46880
  auth: "admin",
46633
46881
  timeoutMs: AI_CAP_TRANSPORT_TIMEOUT_MS
46634
46882
  }),
46635
- /** Live vendor enumeration (GET /models etc.). */
46636
- listModels: method(ProfileRefInputSchema, external_exports.array(external_exports.string())),
46883
+ /**
46884
+ * The models a kind offers, for a SAVED profile or an unsaved draft
46885
+ * (`connection`). A mutation, not a query: a draft may carry a key, and a
46886
+ * query's input travels in the URL. Admin: it dials whatever endpoint the
46887
+ * draft names and may resolve a stored key to do it. The answer never
46888
+ * carries a secret — failures are a typed result, never a throw.
46889
+ */
46890
+ listModels: method(LlmListModelsInputSchema, LlmListModelsResultSchema, {
46891
+ kind: "mutation",
46892
+ auth: "admin"
46893
+ }),
46637
46894
  getDefaults: method(external_exports.object({}), external_exports.array(LlmDefaultSchema)),
46638
46895
  setDefault: method(external_exports.object({
46639
46896
  selector: LlmDefaultSelectorSchema,
@@ -50264,123 +50521,6 @@ var notificationRulesCapability = {
50264
50521
  getAlarmSensors: method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" })
50265
50522
  }
50266
50523
  };
50267
- var MethodAccessSchema = external_exports.enum([
50268
- "view",
50269
- "create",
50270
- "delete"
50271
- ]);
50272
- var AllowedProviderSchema = external_exports.union([external_exports.literal("*"), external_exports.array(external_exports.string())]);
50273
- var AllowedDevicesSchema = external_exports.record(external_exports.string(), external_exports.union([external_exports.literal("*"), external_exports.array(external_exports.string())]));
50274
- var CapScopeSchema = external_exports.enum(["device", "system"]);
50275
- var DeviceSelectorSchema = external_exports.discriminatedUnion("kind", [
50276
- external_exports.object({ kind: external_exports.literal("all") }),
50277
- external_exports.object({
50278
- kind: external_exports.literal("ids"),
50279
- ids: external_exports.array(external_exports.number().int()).min(1)
50280
- }),
50281
- external_exports.object({
50282
- kind: external_exports.literal("types"),
50283
- types: external_exports.array(external_exports.enum(DeviceType)).min(1)
50284
- }),
50285
- external_exports.object({
50286
- kind: external_exports.literal("locations"),
50287
- locations: external_exports.array(external_exports.string().min(1)).min(1)
50288
- })
50289
- ]);
50290
- var DeviceTokenScopeSchema = external_exports.object({
50291
- type: external_exports.literal("device"),
50292
- /** The device SET this grant covers — resolved against the live fleet. */
50293
- selector: DeviceSelectorSchema,
50294
- access: external_exports.array(MethodAccessSchema).min(1),
50295
- /**
50296
- * Whether a grant on a PARENT device transparently covers its accessory
50297
- * CHILDREN (siren / floodlight / PIR) via the persisted-parentage walk.
50298
- * Direction is parent → children ONLY.
50299
- *
50300
- * Absent → the matcher DERIVES it from the access flavour: `view`
50301
- * inherits (a camera viewer sees the camera's accessories), `create` /
50302
- * `delete` do NOT (actuating/removing a child is an explicit act the
50303
- * operator must grant on the child, not inherit from the parent). Set it
50304
- * explicitly to override that default per grant.
50305
- */
50306
- includeLinked: external_exports.boolean().optional()
50307
- });
50308
- function migrateLegacyTokenScope(raw) {
50309
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
50310
- if (Reflect.get(raw, "type") !== "device") return raw;
50311
- if (Reflect.get(raw, "selector") !== void 0) return raw;
50312
- const targets = Reflect.get(raw, "targets");
50313
- if (!Array.isArray(targets)) return raw;
50314
- return {
50315
- type: "device",
50316
- selector: {
50317
- kind: "ids",
50318
- ids: targets.map((t) => typeof t === "string" ? Number(t) : t).filter((n) => typeof n === "number" && Number.isInteger(n))
50319
- },
50320
- access: Reflect.get(raw, "access")
50321
- };
50322
- }
50323
- var TokenScopeSchema = external_exports.preprocess(migrateLegacyTokenScope, external_exports.discriminatedUnion("type", [
50324
- external_exports.object({
50325
- type: external_exports.literal("category"),
50326
- target: CapScopeSchema,
50327
- access: external_exports.array(MethodAccessSchema).min(1)
50328
- }),
50329
- external_exports.object({
50330
- type: external_exports.literal("capability"),
50331
- target: external_exports.string(),
50332
- access: external_exports.array(MethodAccessSchema).min(1)
50333
- }),
50334
- external_exports.object({
50335
- type: external_exports.literal("addon"),
50336
- target: external_exports.string(),
50337
- access: external_exports.array(MethodAccessSchema).min(1)
50338
- }),
50339
- DeviceTokenScopeSchema
50340
- ]));
50341
- var UserRecordSchema = external_exports.object({
50342
- id: external_exports.string(),
50343
- username: external_exports.string(),
50344
- passwordHash: external_exports.string(),
50345
- /**
50346
- * Admin bypass. When true, the middleware skips the scope-access
50347
- * check entirely. There is no other axis of privilege; the legacy
50348
- * role enum collapsed onto this boolean in v2.
50349
- */
50350
- isAdmin: external_exports.boolean().default(false),
50351
- allowedProviders: AllowedProviderSchema,
50352
- allowedDevices: AllowedDevicesSchema,
50353
- /**
50354
- * Scopes granted to this user. Admins bypass; their `scopes` is
50355
- * ignored. Non-admins without scopes are locked out of every
50356
- * protected call.
50357
- */
50358
- scopes: external_exports.array(TokenScopeSchema).default([]),
50359
- createdAt: external_exports.number(),
50360
- updatedAt: external_exports.number()
50361
- });
50362
- var ApiKeyRecordSchema = external_exports.object({
50363
- id: external_exports.string(),
50364
- label: external_exports.string(),
50365
- isAdmin: external_exports.boolean().default(false),
50366
- allowedProviders: AllowedProviderSchema,
50367
- allowedDevices: AllowedDevicesSchema,
50368
- tokenHash: external_exports.string(),
50369
- tokenPrefix: external_exports.string(),
50370
- createdAt: external_exports.number(),
50371
- lastUsedAt: external_exports.number().optional()
50372
- });
50373
- var ScopedTokenSchema = external_exports.object({
50374
- id: external_exports.string(),
50375
- userId: external_exports.string(),
50376
- name: external_exports.string(),
50377
- tokenHash: external_exports.string(),
50378
- tokenPrefix: external_exports.string(),
50379
- scopes: external_exports.array(TokenScopeSchema),
50380
- expiresAt: external_exports.number().nullish(),
50381
- lastUsedAt: external_exports.number().nullish(),
50382
- createdAt: external_exports.number()
50383
- });
50384
50524
  var OauthIntegrationDescriptorSchema = external_exports.object({
50385
50525
  /** Stable id used as the `integration=` query param, e.g. 'export-alexa'. */
50386
50526
  integrationId: external_exports.string(),
@@ -70016,26 +70156,6 @@ var ApiKeySummarySchema = external_exports.object({
70016
70156
  createdAt: external_exports.number(),
70017
70157
  lastUsedAt: external_exports.number().optional()
70018
70158
  });
70019
- var ScopedTokenSummarySchema = external_exports.object({
70020
- id: external_exports.string(),
70021
- userId: external_exports.string(),
70022
- name: external_exports.string(),
70023
- tokenPrefix: external_exports.string(),
70024
- scopes: external_exports.array(TokenScopeSchema),
70025
- expiresAt: external_exports.number().nullish(),
70026
- lastUsedAt: external_exports.number().nullish(),
70027
- createdAt: external_exports.number()
70028
- });
70029
- var CreateScopedTokenInputSchema = external_exports.object({
70030
- userId: external_exports.string(),
70031
- name: external_exports.string(),
70032
- scopes: external_exports.array(TokenScopeSchema),
70033
- expiresAt: external_exports.number().optional()
70034
- });
70035
- var CreateScopedTokenResultSchema = external_exports.object({
70036
- token: external_exports.string(),
70037
- record: ScopedTokenSummarySchema
70038
- });
70039
70159
  var OauthSessionSummarySchema = external_exports.object({
70040
70160
  id: external_exports.string(),
70041
70161
  userId: external_exports.string(),
@@ -70122,18 +70242,6 @@ var userManagementCapability = {
70122
70242
  auth: "admin",
70123
70243
  access: "delete"
70124
70244
  }),
70125
- createScopedToken: method(CreateScopedTokenInputSchema, CreateScopedTokenResultSchema, {
70126
- kind: "mutation",
70127
- auth: "admin",
70128
- access: "create"
70129
- }),
70130
- revokeScopedToken: method(external_exports.object({ id: external_exports.string() }), external_exports.object({ success: external_exports.literal(true) }), {
70131
- kind: "mutation",
70132
- auth: "admin",
70133
- access: "delete"
70134
- }),
70135
- validateScopedToken: method(external_exports.object({ token: external_exports.string() }), ScopedTokenSummarySchema.nullable(), { access: "view" }),
70136
- listScopedTokens: method(external_exports.object({ userId: external_exports.string() }), external_exports.array(ScopedTokenSummarySchema), { auth: "admin" }),
70137
70245
  setupTotp: method(external_exports.object({ userId: external_exports.string() }), TotpSetupResultSchema, {
70138
70246
  kind: "mutation",
70139
70247
  auth: "admin",
@@ -74811,7 +74919,7 @@ var METHOD_ACCESS_MAP = Object.freeze({
74811
74919
  capName: "llm",
74812
74920
  capScope: "system",
74813
74921
  addonId: null,
74814
- access: "view"
74922
+ access: "create"
74815
74923
  },
74816
74924
  "llm.listNodeModels": {
74817
74925
  capName: "llm",
@@ -79475,12 +79583,6 @@ var METHOD_ACCESS_MAP = Object.freeze({
79475
79583
  addonId: null,
79476
79584
  access: "create"
79477
79585
  },
79478
- "userManagement.createScopedToken": {
79479
- capName: "user-management",
79480
- capScope: "system",
79481
- addonId: null,
79482
- access: "create"
79483
- },
79484
79586
  "userManagement.createUser": {
79485
79587
  capName: "user-management",
79486
79588
  capScope: "system",
@@ -79529,12 +79631,6 @@ var METHOD_ACCESS_MAP = Object.freeze({
79529
79631
  addonId: null,
79530
79632
  access: "view"
79531
79633
  },
79532
- "userManagement.listScopedTokens": {
79533
- capName: "user-management",
79534
- capScope: "system",
79535
- addonId: null,
79536
- access: "view"
79537
- },
79538
79634
  "userManagement.listUsers": {
79539
79635
  capName: "user-management",
79540
79636
  capScope: "system",
@@ -79589,12 +79685,6 @@ var METHOD_ACCESS_MAP = Object.freeze({
79589
79685
  addonId: null,
79590
79686
  access: "delete"
79591
79687
  },
79592
- "userManagement.revokeScopedToken": {
79593
- capName: "user-management",
79594
- capScope: "system",
79595
- addonId: null,
79596
- access: "delete"
79597
- },
79598
79688
  "userManagement.setupTotp": {
79599
79689
  capName: "user-management",
79600
79690
  capScope: "system",
@@ -79625,12 +79715,6 @@ var METHOD_ACCESS_MAP = Object.freeze({
79625
79715
  addonId: null,
79626
79716
  access: "view"
79627
79717
  },
79628
- "userManagement.validateScopedToken": {
79629
- capName: "user-management",
79630
- capScope: "system",
79631
- addonId: null,
79632
- access: "view"
79633
- },
79634
79718
  "userManagement.verifyTotp": {
79635
79719
  capName: "user-management",
79636
79720
  capScope: "system",
@@ -85953,6 +86037,7 @@ import * as clack from "@clack/prompts";
85953
86037
  import {
85954
86038
  clearSession,
85955
86039
  defaultSession,
86040
+ jwtClaims,
85956
86041
  listSessions,
85957
86042
  loadSession,
85958
86043
  saveSession
@@ -85968,20 +86053,11 @@ import {
85968
86053
  validateHubAddress
85969
86054
  } from "@camstack/develop";
85970
86055
  import {
85971
- discoverHubs,
85972
- normalizeHubUrl
86056
+ discoverHubs
85973
86057
  } from "@camstack/develop/hub-discovery";
85974
- var ADMIN_TOKEN_SUFFIX = ".admin-token";
85975
86058
  function validateManualHubUrl(value) {
85976
86059
  return validateHubAddress(value);
85977
86060
  }
85978
- function hubUrlFromAdminTokenFile(fileName) {
85979
- if (!fileName.endsWith(ADMIN_TOKEN_SUFFIX)) return null;
85980
- const slug = fileName.slice(0, -ADMIN_TOKEN_SUFFIX.length);
85981
- const match = /^(.+?)_(\d{1,5})$/.exec(slug);
85982
- const candidate = match ? `https://${match[1]}:${match[2]}` : `https://${slug}`;
85983
- return normalizeHubUrl(candidate)?.url ?? null;
85984
- }
85985
86061
  function knownHubCandidates(deps) {
85986
86062
  const dir = deps.sessionDir ?? defaultSessionDir();
85987
86063
  const env = deps.env ?? process.env;
@@ -86004,9 +86080,6 @@ function knownHubCandidates(deps) {
86004
86080
  }
86005
86081
  } catch {
86006
86082
  }
86007
- } else {
86008
- const url2 = hubUrlFromAdminTokenFile(file2);
86009
- if (url2 !== null) out.push({ url: url2, source: "saved admin token" });
86010
86083
  }
86011
86084
  }
86012
86085
  const fromEnv = resolveHubUrl({ env, session: null });
@@ -86134,30 +86207,32 @@ function isLoginPayload(value) {
86134
86207
  const u = v.user;
86135
86208
  return typeof u.id === "string" && typeof u.username === "string";
86136
86209
  }
86137
- function isLogoutPayload(value) {
86138
- if (value === null || typeof value !== "object") return false;
86139
- return Reflect.get(value, "success") === true && typeof Reflect.get(value, "revoked") === "number";
86140
- }
86141
- var SCOPED_TOKEN_PREFIX = "cst_";
86142
- var ADMIN_TOKEN_PREFIX = "csa_";
86143
- async function revokePriorSession(server, prior, authJwt) {
86144
- if (prior.token.startsWith(SCOPED_TOKEN_PREFIX) && prior.tokenId) {
86145
- await callTrpcMutation(
86146
- `${server}/trpc/userManagement.revokeScopedToken?batch=1`,
86147
- `Bearer ${authJwt}`,
86148
- { id: prior.tokenId },
86149
- isUnknown
86150
- );
86151
- return;
86210
+ function revocationFor(session) {
86211
+ if (session.tokenId) {
86212
+ return {
86213
+ procedure: "auth.revokeToken",
86214
+ input: { id: session.tokenId },
86215
+ bearer: "fresh"
86216
+ };
86152
86217
  }
86153
- if (!prior.token.startsWith(SCOPED_TOKEN_PREFIX) && !prior.token.startsWith(ADMIN_TOKEN_PREFIX)) {
86154
- await callTrpcMutation(
86155
- `${server}/trpc/auth.logout?batch=1`,
86156
- `Bearer ${prior.token}`,
86157
- {},
86158
- isLogoutPayload
86159
- );
86218
+ if (jwtClaims(session.token) !== null) {
86219
+ return { procedure: "auth.logout", input: {}, bearer: "self" };
86160
86220
  }
86221
+ return null;
86222
+ }
86223
+ async function performRevocation(server, session, freshJwt) {
86224
+ const r = revocationFor(session);
86225
+ if (!r) return;
86226
+ const bearer = r.bearer === "fresh" && freshJwt ? freshJwt : session.token;
86227
+ await callTrpcMutation(
86228
+ `${server}/trpc/${r.procedure}?batch=1`,
86229
+ `Bearer ${bearer}`,
86230
+ r.input,
86231
+ isUnknown
86232
+ );
86233
+ }
86234
+ async function revokePriorSession(server, prior, authJwt) {
86235
+ await performRevocation(server, prior, authJwt);
86161
86236
  }
86162
86237
  async function completeSecondFactor(server, login) {
86163
86238
  const factors = login.secondFactors ?? [];
@@ -86174,7 +86249,7 @@ async function completeSecondFactor(server, login) {
86174
86249
  return await callTrpcMutation(
86175
86250
  `${server}/trpc/auth.loginVerifyTotp?batch=1`,
86176
86251
  void 0,
86177
- { challengeToken: login.token, code },
86252
+ { challengeToken: login.token, code, refreshable: true },
86178
86253
  isLoginPayload
86179
86254
  );
86180
86255
  } catch (err) {
@@ -86267,6 +86342,8 @@ async function loginCommand(opts) {
86267
86342
  let displayName;
86268
86343
  let userId;
86269
86344
  let isAdmin = false;
86345
+ let refreshToken;
86346
+ let expiresAt;
86270
86347
  while (true) {
86271
86348
  const authSpinner = clack.spinner();
86272
86349
  authSpinner.start(
@@ -86276,7 +86353,7 @@ async function loginCommand(opts) {
86276
86353
  const first = await callTrpcMutation(
86277
86354
  `${server}/trpc/auth.login?batch=1`,
86278
86355
  void 0,
86279
- { username, password: password2 },
86356
+ { username, password: password2, refreshable: true },
86280
86357
  isLoginPayload
86281
86358
  );
86282
86359
  const owesSecondFactor = (first.secondFactors ?? []).length > 0;
@@ -86286,6 +86363,8 @@ async function loginCommand(opts) {
86286
86363
  displayName = login.user.username;
86287
86364
  userId = login.user.id;
86288
86365
  isAdmin = login.user.isAdmin === true;
86366
+ refreshToken = login.refreshToken;
86367
+ expiresAt = login.expiresAt;
86289
86368
  if (!owesSecondFactor) authSpinner.stop(`Authenticated as ${displayName}`);
86290
86369
  break;
86291
86370
  } catch (err) {
@@ -86317,14 +86396,14 @@ async function loginCommand(opts) {
86317
86396
  token: jwt2,
86318
86397
  scopes: [],
86319
86398
  createdAt: Date.now(),
86320
- ...isAdmin ? { isAdmin: true } : {}
86399
+ ...isAdmin ? { isAdmin: true } : {},
86400
+ ...refreshToken ? { refreshToken } : {},
86401
+ ...expiresAt !== void 0 ? { expiresAt } : {}
86321
86402
  };
86322
86403
  const file2 = saveSession(session);
86323
86404
  const role = isAdmin ? "administrator" : "user";
86324
- clack.outro(
86325
- `\u2713 Logged in as ${displayName} (${role}) \u2192 ${server}
86326
- Cached at ${file2}`
86327
- );
86405
+ clack.outro(`\u2713 Logged in as ${displayName} (${role}) \u2192 ${server}
86406
+ Cached at ${file2}`);
86328
86407
  }
86329
86408
  async function logoutCommand(opts) {
86330
86409
  const session = loadSession(opts.server);
@@ -86336,21 +86415,7 @@ async function logoutCommand(opts) {
86336
86415
  const spinner3 = clack.spinner();
86337
86416
  spinner3.start(`Revoking token on ${session.server}`);
86338
86417
  try {
86339
- if (session.token.startsWith(SCOPED_TOKEN_PREFIX) && session.tokenId) {
86340
- await callTrpcMutation(
86341
- `${session.server}/trpc/userManagement.revokeScopedToken?batch=1`,
86342
- `Bearer ${session.token}`,
86343
- { id: session.tokenId },
86344
- isUnknown
86345
- );
86346
- } else if (!session.token.startsWith(SCOPED_TOKEN_PREFIX) && !session.token.startsWith(ADMIN_TOKEN_PREFIX)) {
86347
- await callTrpcMutation(
86348
- `${session.server}/trpc/auth.logout?batch=1`,
86349
- `Bearer ${session.token}`,
86350
- {},
86351
- isLogoutPayload
86352
- );
86353
- }
86418
+ await performRevocation(session.server, session, void 0);
86354
86419
  spinner3.stop("Session revoked server-side.");
86355
86420
  } catch (err) {
86356
86421
  spinner3.stop(
@@ -86396,7 +86461,15 @@ async function whoamiCommand(opts) {
86396
86461
  if (session.tokenId) console.log(` tokenId: ${session.tokenId}`);
86397
86462
  const scopeLine = session.scopes.length > 0 ? session.scopes.map((s) => `${s.type}:${s.target}`).join(", ") : "(login JWT)";
86398
86463
  console.log(` scopes: ${scopeLine}`);
86399
- console.log(` admin: ${session.isAdmin === true ? "yes" : "no"}`);
86464
+ const claims = jwtClaims(session.token);
86465
+ const admin = session.isAdmin === true || claims?.["isAdmin"] === true;
86466
+ console.log(` admin: ${admin ? "yes" : "no"}`);
86467
+ const expiresAt = session.expiresAt ?? (typeof claims?.["exp"] === "number" ? claims["exp"] * 1e3 : void 0);
86468
+ if (expiresAt !== void 0) {
86469
+ console.log(
86470
+ ` expires: ${new Date(expiresAt).toISOString()}${session.refreshToken ? " (renewed automatically)" : ""}`
86471
+ );
86472
+ }
86400
86473
  console.log(` createdAt: ${new Date(session.createdAt).toISOString()}`);
86401
86474
  console.log("");
86402
86475
  console.log(`[camstack] Pinging ${session.server}/api/auth/whoami\u2026`);
@@ -86441,7 +86514,7 @@ import {
86441
86514
  MissingCredentialsError,
86442
86515
  normalizeHubAddress as normalizeHubAddress3,
86443
86516
  touchSession as touchSession3,
86444
- resolveCredentials as resolveCredentials3
86517
+ resolveFreshCredentials as resolveFreshCredentials3
86445
86518
  } from "@camstack/develop";
86446
86519
 
86447
86520
  // src/commands/discover.ts
@@ -86688,7 +86761,20 @@ import * as fs7 from "fs";
86688
86761
  import * as path7 from "path";
86689
86762
  import { parseArgs as parseArgs6 } from "util";
86690
86763
  import * as clack3 from "@clack/prompts";
86691
- import { loadSession as loadSession2, resolveCredentials, touchSession } from "@camstack/develop";
86764
+ import { loadSession as loadSession2, resolveFreshCredentials, touchSession } from "@camstack/develop";
86765
+
86766
+ // src/http/hub-transport.ts
86767
+ var cliHubTransport = async (req) => {
86768
+ const res = await hubRequest(req.url, {
86769
+ method: req.method,
86770
+ headers: req.headers,
86771
+ ...req.body !== void 0 ? { body: req.body } : {},
86772
+ timeoutMs: req.timeoutMs
86773
+ });
86774
+ return { status: res.status, text: await res.text() };
86775
+ };
86776
+
86777
+ // src/commands/dev.ts
86692
86778
  var DEFAULT_DEBOUNCE_MS = 500;
86693
86779
  var DEFAULT_WATCH_SUBDIR = "src";
86694
86780
  function resolveAddonDir(arg) {
@@ -86720,12 +86806,12 @@ function watchRecursive(target, onEvent) {
86720
86806
  return { close: () => w.close(), recursive: false };
86721
86807
  }
86722
86808
  }
86723
- async function pushOnce(addonPath, opts, label) {
86809
+ async function pushOnce(addonPath, getOpts, label) {
86724
86810
  const start = Date.now();
86725
86811
  console.log(`
86726
86812
  [camstack dev] \u2192 ${label}\u2026`);
86727
86813
  try {
86728
- await deployAddon(addonPath, opts);
86814
+ await deployAddon(addonPath, await getOpts());
86729
86815
  const took = ((Date.now() - start) / 1e3).toFixed(1);
86730
86816
  console.log(`[camstack dev] \u2713 Synced in ${took}s`);
86731
86817
  } catch (err) {
@@ -86754,12 +86840,14 @@ async function runDev(args) {
86754
86840
  });
86755
86841
  const addonArg = positionals[0] ?? ".";
86756
86842
  const addonDir = resolveAddonDir(addonArg);
86757
- const creds = resolveCredentials({
86843
+ const credentialInputs = {
86758
86844
  ...typeof values.server === "string" ? { server: values.server } : {},
86759
86845
  ...typeof values.token === "string" ? { token: values.token } : {},
86760
86846
  ...typeof values["token-file"] === "string" ? { tokenFile: values["token-file"] } : {},
86761
- loadSession: loadSession2
86762
- });
86847
+ loadSession: loadSession2,
86848
+ transport: cliHubTransport
86849
+ };
86850
+ const creds = await resolveFreshCredentials(credentialInputs);
86763
86851
  if (creds.warning) console.error(`[camstack dev] Warning: ${creds.warning}`);
86764
86852
  if (creds.source === "session" && creds.server) touchSession(creds.server);
86765
86853
  const serverUrl = creds.server;
@@ -86778,6 +86866,10 @@ async function runDev(args) {
86778
86866
  buildMode: values["no-build"] === true ? "skip" : "auto",
86779
86867
  ...typeof values["build-script"] === "string" ? { buildScript: values["build-script"] } : {}
86780
86868
  };
86869
+ const freshOpts = async () => ({
86870
+ ...deployOpts,
86871
+ token: (await resolveFreshCredentials(credentialInputs)).token
86872
+ });
86781
86873
  const watchOverride = typeof values["watch-path"] === "string" ? values["watch-path"] : void 0;
86782
86874
  const watchTarget = watchOverride ? path7.resolve(addonDir, watchOverride) : fs7.existsSync(path7.join(addonDir, DEFAULT_WATCH_SUBDIR)) ? path7.join(addonDir, DEFAULT_WATCH_SUBDIR) : addonDir;
86783
86875
  if (!fs7.existsSync(watchTarget)) {
@@ -86791,7 +86883,7 @@ async function runDev(args) {
86791
86883
  );
86792
86884
  clack3.log.info(`Debounce: ${debounceMs}ms`);
86793
86885
  if (values["no-initial-push"] !== true) {
86794
- await pushOnce(addonDir, deployOpts, "Initial sync");
86886
+ await pushOnce(addonDir, freshOpts, "Initial sync");
86795
86887
  } else {
86796
86888
  console.log("[camstack dev] Skipping initial push (--no-initial-push). Waiting for changes\u2026");
86797
86889
  }
@@ -86807,7 +86899,7 @@ async function runDev(args) {
86807
86899
  }
86808
86900
  pushing = true;
86809
86901
  try {
86810
- await pushOnce(addonDir, deployOpts, "File change detected \u2014 rebuilding");
86902
+ await pushOnce(addonDir, freshOpts, "File change detected \u2014 rebuilding");
86811
86903
  } finally {
86812
86904
  pushing = false;
86813
86905
  if (pending) {
@@ -86843,7 +86935,7 @@ import * as clack4 from "@clack/prompts";
86843
86935
  import {
86844
86936
  loadSession as loadSession3,
86845
86937
  touchSession as touchSession2,
86846
- resolveCredentials as resolveCredentials2,
86938
+ resolveFreshCredentials as resolveFreshCredentials2,
86847
86939
  withAuthHint as withAuthHint3
86848
86940
  } from "@camstack/develop";
86849
86941
  var POLL_INTERVAL_MS2 = 2e3;
@@ -86907,12 +86999,14 @@ async function runWatch(args) {
86907
86999
  allowPositionals: true
86908
87000
  });
86909
87001
  const addonArg = positionals[0] ?? ".";
86910
- const creds = resolveCredentials2({
87002
+ const credentialInputs = {
86911
87003
  ...typeof values.server === "string" ? { server: values.server } : {},
86912
87004
  ...typeof values.token === "string" ? { token: values.token } : {},
86913
87005
  ...typeof values["token-file"] === "string" ? { tokenFile: values["token-file"] } : {},
86914
- loadSession: loadSession3
86915
- });
87006
+ loadSession: loadSession3,
87007
+ transport: cliHubTransport
87008
+ };
87009
+ const creds = await resolveFreshCredentials2(credentialInputs);
86916
87010
  if (creds.warning) console.error(`[camstack watch] Warning: ${creds.warning}`);
86917
87011
  if (creds.source === "session" && creds.server) touchSession2(creds.server);
86918
87012
  const serverUrl = creds.server;
@@ -86951,7 +87045,14 @@ async function runWatch(args) {
86951
87045
  process.on("SIGTERM", shutdown);
86952
87046
  while (!stop) {
86953
87047
  try {
86954
- const entries2 = await fetchLogs(serverUrl, token, addonId, LOG_BATCH_LIMIT, creds.source);
87048
+ const fresh = await resolveFreshCredentials2(credentialInputs);
87049
+ const entries2 = await fetchLogs(
87050
+ serverUrl,
87051
+ fresh.token,
87052
+ addonId,
87053
+ LOG_BATCH_LIMIT,
87054
+ creds.source
87055
+ );
86955
87056
  const sorted = [...entries2].toSorted((a, b) => {
86956
87057
  const ta = typeof a.timestamp === "number" ? a.timestamp : new Date(a.timestamp).getTime();
86957
87058
  const tb = typeof b.timestamp === "number" ? b.timestamp : new Date(b.timestamp).getTime();
@@ -87423,7 +87524,7 @@ function buildCommands() {
87423
87524
  " -p, --password <pwd> Password (skips prompt \u2014 prefer letting the CLI prompt)",
87424
87525
  ` --token-name <name> Ignored (kept for scripts); login uses your hub session JWT`,
87425
87526
  " --admin Ignored (kept for muscle memory); admin follows your account role",
87426
- " --admin-days <n> Ignored (kept for muscle memory); no separate admin-token mint"
87527
+ " --admin-days <n> Ignored (kept for muscle memory); one login, one token format"
87427
87528
  ].join("\n")
87428
87529
  },
87429
87530
  {
@@ -87434,7 +87535,7 @@ function buildCommands() {
87434
87535
  "Usage: camstack discover [options]",
87435
87536
  "",
87436
87537
  "Lists the hubs `camstack login` would offer: those announcing _camstack._tcp over",
87437
- " mDNS plus saved sessions, admin-token files, $CAMSTACK_HUB_URL and scratchpad/.hub-url,",
87538
+ " mDNS plus saved sessions, $CAMSTACK_HUB_URL and scratchpad/.hub-url,",
87438
87539
  " reachable ones only, each with its source. Agents never announce this service.",
87439
87540
  "",
87440
87541
  "Options:",
@@ -87711,7 +87812,7 @@ async function runWhoami(args) {
87711
87812
  const server = stringOpt(parsed.values, "server");
87712
87813
  await whoamiCommand(server ? { server: normalizeHubAddress3(server) } : {});
87713
87814
  }
87714
- function resolveClosureDeployOpts(values) {
87815
+ async function resolveClosureDeployOpts(values) {
87715
87816
  const nodeId = stringOpt(values, "node");
87716
87817
  const cluster = boolOpt(values, "cluster") || boolOpt(values, "all");
87717
87818
  if (cluster && nodeId) {
@@ -87719,7 +87820,7 @@ function resolveClosureDeployOpts(values) {
87719
87820
  process.exit(1);
87720
87821
  }
87721
87822
  const version2 = stringOpt(values, "version");
87722
- const creds = resolveCommandCredentials(values);
87823
+ const creds = await resolveCommandCredentials(values);
87723
87824
  return {
87724
87825
  serverUrl: creds.server ?? DEFAULT_SERVER_URL,
87725
87826
  token: creds.token,
@@ -87757,7 +87858,7 @@ async function runDeploy(args) {
87757
87858
  console.error("[camstack] Error: --closure does not take addon --build / --no-build flags.");
87758
87859
  process.exit(1);
87759
87860
  }
87760
- await deployServer(resolveClosureDeployOpts(parsed.values));
87861
+ await deployServer(await resolveClosureDeployOpts(parsed.values));
87761
87862
  return;
87762
87863
  }
87763
87864
  if (stringOpt(parsed.values, "version")) {
@@ -87765,7 +87866,7 @@ async function runDeploy(args) {
87765
87866
  process.exit(1);
87766
87867
  }
87767
87868
  const addonPath = parsed.positionals[0] ?? ".";
87768
- const creds = resolveCommandCredentials(parsed.values);
87869
+ const creds = await resolveCommandCredentials(parsed.values);
87769
87870
  const server = creds.server ?? DEFAULT_SERVER_URL;
87770
87871
  const token = creds.token;
87771
87872
  const nodeId = stringOpt(parsed.values, "node");
@@ -87817,19 +87918,20 @@ async function runDeployServer(args) {
87817
87918
  return;
87818
87919
  }
87819
87920
  console.log("[camstack] note: `deploy-server` is an alias of `deploy --closure`");
87820
- await deployServer(resolveClosureDeployOpts(parsed.values));
87921
+ await deployServer(await resolveClosureDeployOpts(parsed.values));
87821
87922
  }
87822
87923
  var DEFAULT_SERVER_URL = "https://localhost:4443";
87823
- function resolveCommandCredentials(values) {
87924
+ async function resolveCommandCredentials(values) {
87824
87925
  const server = stringOpt(values, "server");
87825
87926
  const token = stringOpt(values, "token");
87826
87927
  const tokenFile = stringOpt(values, "token-file");
87827
87928
  try {
87828
- const creds = resolveCredentials3({
87929
+ const creds = await resolveFreshCredentials3({
87829
87930
  ...server ? { server } : {},
87830
87931
  ...token ? { token } : {},
87831
87932
  ...tokenFile ? { tokenFile } : {},
87832
- loadSession: loadSession4
87933
+ loadSession: loadSession4,
87934
+ transport: cliHubTransport
87833
87935
  });
87834
87936
  if (creds.warning) console.error(`[camstack] Warning: ${creds.warning}`);
87835
87937
  if (creds.source === "session" && creds.server) touchSession3(creds.server);