@camstack/system 1.2.164 → 1.2.166

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.
Files changed (68) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  11. package/dist/builtins/console-logging/index.js +1 -1
  12. package/dist/builtins/console-logging/index.mjs +1 -1
  13. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  14. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  15. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  16. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  19. package/dist/builtins/hub-forwarder/index.js +1 -1
  20. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  21. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  23. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  25. package/dist/builtins/local-network/local-network.addon.js +1 -1
  26. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  27. package/dist/builtins/loki-logging/index.js +1 -1
  28. package/dist/builtins/loki-logging/index.mjs +1 -1
  29. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  30. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  31. package/dist/builtins/platform-probe/index.js +1 -1
  32. package/dist/builtins/platform-probe/index.mjs +1 -1
  33. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  34. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  35. package/dist/builtins/snapshot/index.js +1 -1
  36. package/dist/builtins/snapshot/index.mjs +1 -1
  37. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  38. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  39. package/dist/builtins/sqlite-storage/index.d.ts +1 -1
  40. package/dist/builtins/sqlite-storage/index.js +2 -0
  41. package/dist/builtins/sqlite-storage/index.mjs +2 -2
  42. package/dist/builtins/sqlite-storage/query-profiler.d.ts +21 -0
  43. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  44. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  45. package/dist/builtins/storage-orchestrator/location-occupancy.d.ts +19 -0
  46. package/dist/builtins/storage-orchestrator/storage-cleanup-coordinator.d.ts +68 -0
  47. package/dist/builtins/storage-orchestrator/storage-migration-coordinator.d.ts +14 -0
  48. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +13 -8
  49. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +441 -100
  50. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +443 -100
  51. package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +11 -13
  52. package/dist/builtins/system-config/system-config.addon.js +1 -1
  53. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  54. package/dist/builtins/winston-logging/index.js +1 -1
  55. package/dist/builtins/winston-logging/index.mjs +1 -1
  56. package/dist/{dist-BhE8zNfY.js → dist-CFTKQGym.js} +185 -7
  57. package/dist/{dist-BpsHt11f.mjs → dist-Dw9cm1NS.mjs} +180 -8
  58. package/dist/index.js +2 -2
  59. package/dist/index.mjs +2 -2
  60. package/dist/kernel/deps/manifest-system-deps.d.ts +5 -2
  61. package/dist/kernel/deps/system-package-allowlist.d.ts +12 -0
  62. package/dist/kernel/deps/system-package-broker.d.ts +31 -0
  63. package/dist/kernel/deps/system-package-client.d.ts +9 -0
  64. package/dist/{manifest-system-deps-CJLqfJUs.js → manifest-system-deps-BIxY1Y5e.js} +140 -5
  65. package/dist/{manifest-system-deps-Bk_XLYbB.mjs → manifest-system-deps-DTz_zNQf.mjs} +142 -6
  66. package/dist/{retired-settings-keys-CqDbI-vK.js → retired-settings-keys-dehyu2N3.js} +1 -1
  67. package/dist/{retired-settings-keys-DLwieFXR.mjs → retired-settings-keys-diW1NmyP.mjs} +1 -1
  68. package/package.json +1 -1
@@ -4270,6 +4270,13 @@ var MediaRelocateModeSchema = z.enum([
4270
4270
  ]);
4271
4271
  var RelocateMediaInputSchema = z.object({
4272
4272
  toLocationId: z.string(),
4273
+ /**
4274
+ * Restrict the pass to rows currently on this location. Omitted / `'*'` =
4275
+ * every row that is not already on `toLocationId` (the historical
4276
+ * behaviour). A named source is what a from→to migration needs: without it
4277
+ * "move events off disk 2" also emptied disk 1.
4278
+ */
4279
+ fromLocationId: z.string().optional(),
4273
4280
  throttleMbps: z.number().min(1).max(1e3).optional(),
4274
4281
  /** Omitted = `move`, the pre-existing behaviour. */
4275
4282
  mode: MediaRelocateModeSchema.optional()
@@ -4337,6 +4344,19 @@ var StorageMigrationDestinationsSchema = z.object({
4337
4344
  galleryMedia: z.string().min(1).optional()
4338
4345
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
4339
4346
  /**
4347
+ * Optional named source per class. Omitted = the class's current default
4348
+ * (the historical behaviour). A named source that is NOT the default is a
4349
+ * drain of that disk: bytes move, the default stays, and the source is
4350
+ * disabled when the move finishes.
4351
+ */
4352
+ var StorageMigrationSourcesSchema = z.object({
4353
+ recordings: z.string().min(1).optional(),
4354
+ recordingsLow: z.string().min(1).optional(),
4355
+ eventMedia: z.string().min(1).optional(),
4356
+ backups: z.string().min(1).optional(),
4357
+ galleryMedia: z.string().min(1).optional()
4358
+ }).optional();
4359
+ /**
4340
4360
  * How a migration sequences the cutover against the byte move.
4341
4361
  *
4342
4362
  * - `blocking` — the historical order: pause, move every byte, repoint,
@@ -4358,6 +4378,8 @@ var StorageMigrationModeSchema = z.enum(["blocking", "nonBlocking"]);
4358
4378
  /** Shared input for planning and starting an orchestrated storage migration. */
4359
4379
  var StorageMigrationInputSchema = z.object({
4360
4380
  destinations: StorageMigrationDestinationsSchema,
4381
+ /** Omitted = each class's current default. */
4382
+ sources: StorageMigrationSourcesSchema,
4361
4383
  throttleMbps: z.number().min(1).max(1e3).optional(),
4362
4384
  /** Omitted = `blocking`, which stays the default. */
4363
4385
  mode: StorageMigrationModeSchema.optional()
@@ -4437,6 +4459,13 @@ var StorageMigrationMoveSchema = z.object({
4437
4459
  storageClass: StorageMigrationClassSchema,
4438
4460
  fromLocationId: z.string(),
4439
4461
  toLocationId: z.string(),
4462
+ /**
4463
+ * True when `from` was NOT the class default at plan time. The move still
4464
+ * copies bytes, but the default is left alone and the source is disabled
4465
+ * once the copy verifies. Absent on jobs planned before this field existed
4466
+ * — those jobs always repointed, which is `false`.
4467
+ */
4468
+ freezeSource: z.boolean().optional(),
4440
4469
  moverJobId: z.string().nullable(),
4441
4470
  state: RelocateJobStateSchema.nullable(),
4442
4471
  error: z.string().nullable(),
@@ -4450,6 +4479,7 @@ var StorageMigrationJobSchema = z.object({
4450
4479
  * can tell a seconds-long cutover from a thirty-hour one. */
4451
4480
  mode: StorageMigrationModeSchema,
4452
4481
  destinations: StorageMigrationDestinationsSchema,
4482
+ sources: StorageMigrationSourcesSchema,
4453
4483
  throttleMbps: z.number(),
4454
4484
  moves: z.array(StorageMigrationMoveSchema),
4455
4485
  pauseLeaseId: z.string().nullable(),
@@ -4499,6 +4529,7 @@ var StorageMigrationFindingSchema = z.object({
4499
4529
  });
4500
4530
  var StorageMigrationPlanSchema = z.object({
4501
4531
  destinations: StorageMigrationDestinationsSchema,
4532
+ sources: StorageMigrationSourcesSchema,
4502
4533
  /** The mode this plan was built for. A plan is only valid for its mode: the
4503
4534
  * `eventMedia` seal gate and the single-cardinality refusal both depend on
4504
4535
  * it. */
@@ -4506,7 +4537,8 @@ var StorageMigrationPlanSchema = z.object({
4506
4537
  moves: z.array(z.object({
4507
4538
  storageClass: StorageMigrationClassSchema,
4508
4539
  fromLocationId: z.string(),
4509
- toLocationId: z.string()
4540
+ toLocationId: z.string(),
4541
+ freezeSource: z.boolean().optional()
4510
4542
  })),
4511
4543
  findings: z.array(StorageMigrationFindingSchema)
4512
4544
  });
@@ -4692,10 +4724,51 @@ var LedgerWalkReportSchema = z.object({
4692
4724
  var RelocatableMediaCountSchema = z.object({ rows: z.number().int().nonnegative() }).nullable();
4693
4725
  var RelocatableMediaCountInputSchema = z.object({
4694
4726
  toLocationId: z.string().min(1),
4727
+ /** Restrict the count to one source; omitted / `'*'` = every non-target row. */
4728
+ fromLocationId: z.string().optional(),
4695
4729
  /** Omitted = `move`. */
4696
4730
  mode: MediaRelocateModeSchema.optional()
4697
4731
  });
4698
4732
  /**
4733
+ * Operator cleanup of leftover analytics rows, optional debug media, and
4734
+ * ghost ledger entries on frozen footage locations.
4735
+ *
4736
+ * A pass is tens of minutes on a standing backlog. The hub method RETURNS
4737
+ * `{ jobId }` immediately; progress is `cleanupStatus`. Awaiting the work
4738
+ * is how `addons.custom` hit the 60 s UDS deadline while reclaim continued
4739
+ * with no operator-visible status.
4740
+ */
4741
+ var StorageCleanupPhaseSchema = z.enum([
4742
+ "orphans",
4743
+ "debug-media",
4744
+ "ghost-ledger",
4745
+ "done",
4746
+ "failed",
4747
+ "cancelled"
4748
+ ]);
4749
+ var StorageCleanupInputSchema = z.object({
4750
+ /** Also walk motion stills / track filmstrips. Off by default. */
4751
+ includeDebugMedia: z.boolean().optional() });
4752
+ var StorageCleanupJobSchema = z.object({
4753
+ jobId: z.string(),
4754
+ phase: StorageCleanupPhaseSchema,
4755
+ includeDebugMedia: z.boolean(),
4756
+ orphansReclaimed: z.number().int().nonnegative(),
4757
+ orphanBytesReclaimed: z.number().int().nonnegative(),
4758
+ debugMediaReclaimed: z.number().int().nonnegative(),
4759
+ debugMediaBytesReclaimed: z.number().int().nonnegative(),
4760
+ ghostsForgotten: z.number().int().nonnegative(),
4761
+ ghostBytesForgotten: z.number().int().nonnegative(),
4762
+ /** Short operator-facing line: current collection, pass, or location. */
4763
+ detail: z.string().nullable(),
4764
+ cancelRequested: z.boolean(),
4765
+ startedAt: z.number(),
4766
+ updatedAt: z.number(),
4767
+ finishedAt: z.number().nullable(),
4768
+ error: z.string().nullable()
4769
+ });
4770
+ var StorageCleanupStatusInputSchema = z.object({ jobId: z.string().optional() });
4771
+ /**
4699
4772
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
4700
4773
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
4701
4774
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -4723,11 +4796,10 @@ var StorageLocationTypeSchema = z.string().regex(/^[a-z][a-zA-Z0-9-]*$/);
4723
4796
  * The default location for a type uses `id === <type>:default` by
4724
4797
  * convention (the bare type ref like `'backups'` resolves to it).
4725
4798
  *
4726
- * `isSystem: true` marks a location as orchestrator-seeded and
4727
- * undeletable. The bootstrap-installed defaults (one per type) carry
4728
- * this flag; operator-added locations don't. Editing the config of
4729
- * a system location is allowed (path migration, provider swap) but
4730
- * deleting it is rejected at the cap level.
4799
+ * `isSystem` is a legacy persisted flag. Seed still creates the initial
4800
+ * `<type>:default` locations; the flag is no longer a lock, a badge, or a
4801
+ * prune selector. New writes leave it false. Deletion is gated on uniqueness
4802
+ * / last-enabled, not on this bit.
4731
4803
  */
4732
4804
  var StorageLocationSchema = z.object({
4733
4805
  id: z.string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/),
@@ -21633,7 +21705,23 @@ var storageMigrationCapability = {
21633
21705
  drain: method(StorageMigrationDrainInputSchema, z.object({ jobId: z.string() }), {
21634
21706
  kind: "mutation",
21635
21707
  auth: "admin"
21636
- })
21708
+ }),
21709
+ /**
21710
+ * One operator cleanup of leftover analytics (DB + blobs) and ghost
21711
+ * ledger rows on frozen footage locations. Optional debug-media sweep.
21712
+ * Returns immediately; poll {@link cleanupStatus}.
21713
+ */
21714
+ cleanupStart: method(StorageCleanupInputSchema, z.object({ jobId: z.string() }), {
21715
+ kind: "mutation",
21716
+ auth: "admin"
21717
+ }),
21718
+ cleanupStatus: method(StorageCleanupStatusInputSchema, StorageCleanupJobSchema.nullable(), { auth: "admin" }),
21719
+ cleanupCancel: method(z.object({ jobId: z.string() }), z.object({ cancelled: z.boolean() }), {
21720
+ kind: "mutation",
21721
+ auth: "admin"
21722
+ }),
21723
+ /** Recent finished migration jobs, newest first. The live job is `status`. */
21724
+ history: method(z.object({}), z.array(StorageMigrationJobSchema).readonly(), { auth: "admin" })
21637
21725
  }
21638
21726
  };
21639
21727
  var ProviderInfoSchema = z.discriminatedUnion("shouldSaveDiskSpace", [z.object({
@@ -29899,6 +29987,33 @@ var RecordingRebalanceInputSchema = z.object({
29899
29987
  minMoveGb: z.number().min(0).optional()
29900
29988
  });
29901
29989
  /**
29990
+ * Operator-facing placement of one camera onto a recordings location.
29991
+ *
29992
+ * `pinLocationId` is the operator instruction: a location id, or `null` for
29993
+ * Auto (the planner may move this camera). `locationId` is where high/mid
29994
+ * currently write — the plan, which may disagree with the pin when Auto.
29995
+ */
29996
+ var RecordingDevicePlacementSchema = z.object({
29997
+ deviceId: z.number().int(),
29998
+ profile: z.string(),
29999
+ locationId: z.string()
30000
+ });
30001
+ var RecordingDevicePinSchema = z.object({
30002
+ deviceId: z.number().int(),
30003
+ /** Recordings-class location this camera is pinned to. */
30004
+ locationId: z.string()
30005
+ });
30006
+ var RecordingPlacementViewSchema = z.object({
30007
+ assignments: z.array(RecordingDevicePlacementSchema),
30008
+ pins: z.array(RecordingDevicePinSchema),
30009
+ defaultLocations: z.record(z.string(), z.string())
30010
+ });
30011
+ var RecordingSetDevicePlacementInputSchema = z.object({
30012
+ deviceId: z.number().int(),
30013
+ /** `null` = Auto. Otherwise a `recordings:*` location id. */
30014
+ locationId: z.string().nullable()
30015
+ });
30016
+ /**
29902
30017
  * Result of locating footage at a wall-clock instant for one device/profile.
29903
30018
  * `segment` carries the covering segment's window; `gap` reports the forward
29904
30019
  * nearest covered edge (`null` past the end of footage / when none exists)
@@ -30251,6 +30366,22 @@ var recordingCapability = {
30251
30366
  startStorageRebalance: method(RecordingRebalanceInputSchema, RecordingRebalancePlanSchema, {
30252
30367
  kind: "mutation",
30253
30368
  auth: "admin"
30369
+ }),
30370
+ /**
30371
+ * The placement plan in force plus operator pins. Drives the Locations
30372
+ * admin page: Auto vs a named recordings location, per camera.
30373
+ */
30374
+ getPlacement: method(z.object({}), RecordingPlacementViewSchema, {
30375
+ kind: "query",
30376
+ auth: "admin"
30377
+ }),
30378
+ /**
30379
+ * Pin a camera to a recordings location, or clear the pin (Auto). High and
30380
+ * mid follow the pin; low stays with the recordingsLow planner.
30381
+ */
30382
+ setDevicePlacement: method(RecordingSetDevicePlacementInputSchema, z.object({ ok: z.literal(true) }), {
30383
+ kind: "mutation",
30384
+ auth: "admin"
30254
30385
  })
30255
30386
  }
30256
30387
  };
@@ -38325,6 +38456,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
38325
38456
  addonId: null,
38326
38457
  access: "view"
38327
38458
  },
38459
+ "recording.getPlacement": {
38460
+ capName: "recording",
38461
+ capScope: "system",
38462
+ addonId: null,
38463
+ access: "view"
38464
+ },
38328
38465
  "recording.getPlaybackManifest": {
38329
38466
  capName: "recording",
38330
38467
  capScope: "system",
@@ -38451,6 +38588,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
38451
38588
  addonId: null,
38452
38589
  access: "create"
38453
38590
  },
38591
+ "recording.setDevicePlacement": {
38592
+ capName: "recording",
38593
+ capScope: "system",
38594
+ addonId: null,
38595
+ access: "create"
38596
+ },
38454
38597
  "recording.startStorageMigrationMove": {
38455
38598
  capName: "recording",
38456
38599
  capScope: "system",
@@ -38895,12 +39038,36 @@ var METHOD_ACCESS_MAP = Object.freeze({
38895
39038
  addonId: null,
38896
39039
  access: "create"
38897
39040
  },
39041
+ "storageMigration.cleanupCancel": {
39042
+ capName: "storage-migration",
39043
+ capScope: "system",
39044
+ addonId: null,
39045
+ access: "create"
39046
+ },
39047
+ "storageMigration.cleanupStart": {
39048
+ capName: "storage-migration",
39049
+ capScope: "system",
39050
+ addonId: null,
39051
+ access: "create"
39052
+ },
39053
+ "storageMigration.cleanupStatus": {
39054
+ capName: "storage-migration",
39055
+ capScope: "system",
39056
+ addonId: null,
39057
+ access: "view"
39058
+ },
38898
39059
  "storageMigration.drain": {
38899
39060
  capName: "storage-migration",
38900
39061
  capScope: "system",
38901
39062
  addonId: null,
38902
39063
  access: "create"
38903
39064
  },
39065
+ "storageMigration.history": {
39066
+ capName: "storage-migration",
39067
+ capScope: "system",
39068
+ addonId: null,
39069
+ access: "view"
39070
+ },
38904
39071
  "storageMigration.movers": {
38905
39072
  capName: "storage-migration",
38906
39073
  capScope: "system",
@@ -41387,6 +41554,11 @@ Object.freeze({
41387
41554
  form: "single",
41388
41555
  optional: false
41389
41556
  }],
41557
+ "recording.setDevicePlacement": [{
41558
+ name: "deviceId",
41559
+ form: "single",
41560
+ optional: false
41561
+ }],
41390
41562
  "recording.startStorageMigrationMove": [{
41391
41563
  name: "deviceId",
41392
41564
  form: "single",
@@ -42678,4 +42850,4 @@ function enumerateInferenceDevices(hw) {
42678
42850
  return out;
42679
42851
  }
42680
42852
  //#endregion
42681
- export { isObjectInput as $, parseJsonUnknown as $t, bareAddonId as A, vectorStoreCapability as At, deviceManagerCapability as B, ReadinessTimeoutError as Bt, UserRecordSchema as C, snapshotCapability as Ct, alertsCapability as D, streamQualityLabel as Dt, addonWidgetsCapability as E, storageProviderCapability as Et, coreBlockIdFromAddonId as F, DEVICE_STATUS_METHOD as Ft, enumerateItemArrayFields as G, createEvent as Gt, deviceStatusCapability as H, asJsonObject as Ht, coreBlocksCapability as I, DeviceFeature as It, extractNestedAddonId as J, expandCapMethods as Jt, enumerateSchemaFields as K, emitDownForOwnedCaps as Kt, dataStoreProviderCapability as L, DeviceRole as Lt, buildStreamParamsConfigSchema as M, BaseAddon as Mt, collectSecretConfigKeys as N, DATAPLANE_SECRET_HEADER as Nt, authProviderCapability as O, userManagementCapability as Ot, coreBlockAddonId as P, DEVICE_SETTINGS_CONTRIBUTION_METHODS as Pt, isCollectionArrayMethod as Q, parseJsonObject as Qt, decodeVectorBase64 as R, DeviceType as Rt, StorageMigrationJobSchema as S, settingsStoreCapability as St, addonSettingsCapability as T, storageMigrationCapability as Tt, doorbellCapability as U, asNumber as Ut, deviceStateCapability as V, WELL_KNOWN_TAB_MAP as Vt, enumerateInferenceDevices as W, asString as Wt, foldSnapshotByFunction as X, isDeviceConfigCap as Xt, filesystemBrowseCapability as Y, hydrateSchema as Yt, isArrayOutputSchema as Z, nodePin as Zt, SOURCE_DEVICE_TYPES as _, resolveMethodAuth as _t, CAP_NAMES_WITH_STATUS as a, localNetworkCapability as at, ScopedTokenSchema as b, scopesAllowDeviceCap as bt, CoreBlockSchema as c, looseSchema as ct, DeviceStatusSchema as d, objectInputDeclaresAddonId as dt, readinessKey as en, isSameAddonId as et, LOG_LEVEL_RANK as f, parseStreamParamsFormPatch as ft, SOURCE_CAPS as g, resolveBucketMs as gt, RUNTIME_DEFAULTS as h, reducePoints as ht, BatteryStatusSchema as i, EventCategory as in, lifecycleJobSchema as it, batteryCapability as j, errMsg as jt, backupCapability as k, vectorDimFromBase64 as kt, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as l, metricsProviderCapability as lt, REDACTED_SECRET as m, procedureAuthKey as mt, AlertSchema as n, scopeKey as nn, isVoidInput as nt, CORE_BLOCKS_ADDON_ID as o, logDestinationCapability as ot, METHOD_ACCESS_MAP as p, platformProbeCapability as pt, evaluateSensorEdge as q, emitReadiness as qt, ApiKeyRecordSchema as r, sleep as rn, kebabToCamel as rt, CORE_BLOCK_ADDON_PREFIX as s, logLevelAtMost as st, ALL_CAPABILITY_DEFINITIONS as t, resolveCapMount as tn, isSourceCap as tt, DeclaredDevices as u, normalizeUnit as ut, STORAGE_ACCESS_FALLBACK as v, runtimeStatePolicyFor as vt, addonPagesCapability as w, storageCapability as wt, StorageLocationTypeSchema as x, scoreRuntimes as xt, STREAM_PROFILE_META as y, scopesAllowAddon as yt, deriveBatteryPresence as z, ReadinessRegistry as zt };
42853
+ export { isCollectionArrayMethod as $, parseJsonObject as $t, backupCapability as A, vectorDimFromBase64 as At, deriveBatteryPresence as B, ReadinessRegistry as Bt, StorageMigrationJobSchema as C, settingsStoreCapability as Ct, addonWidgetsCapability as D, storageProviderCapability as Dt, addonSettingsCapability as E, storageMigrationCapability as Et, coreBlockAddonId as F, DEVICE_SETTINGS_CONTRIBUTION_METHODS as Ft, enumerateInferenceDevices as G, asString as Gt, deviceStateCapability as H, WELL_KNOWN_TAB_MAP as Ht, coreBlockIdFromAddonId as I, DEVICE_STATUS_METHOD as It, evaluateSensorEdge as J, emitReadiness as Jt, enumerateItemArrayFields as K, createEvent as Kt, coreBlocksCapability as L, DeviceFeature as Lt, batteryCapability as M, errMsg as Mt, buildStreamParamsConfigSchema as N, BaseAddon as Nt, alertsCapability as O, streamQualityLabel as Ot, collectSecretConfigKeys as P, DATAPLANE_SECRET_HEADER as Pt, isArrayOutputSchema as Q, nodePin as Qt, dataStoreProviderCapability as R, DeviceRole as Rt, StorageLocationTypeSchema as S, scoreRuntimes as St, addonPagesCapability as T, storageCapability as Tt, deviceStatusCapability as U, asJsonObject as Ut, deviceManagerCapability as V, ReadinessTimeoutError as Vt, doorbellCapability as W, asNumber as Wt, filesystemBrowseCapability as X, hydrateSchema as Xt, extractNestedAddonId as Y, expandCapMethods as Yt, foldSnapshotByFunction as Z, isDeviceConfigCap as Zt, SOURCE_DEVICE_TYPES as _, resolveBucketMs as _t, CAP_NAMES_WITH_STATUS as a, EventCategory as an, lifecycleJobSchema as at, ScopedTokenSchema as b, scopesAllowAddon as bt, CoreBlockSchema as c, logLevelAtMost as ct, DeviceStatusSchema as d, normalizeUnit as dt, parseJsonUnknown as en, isObjectInput as et, LOG_LEVEL_RANK as f, objectInputDeclaresAddonId as ft, SOURCE_CAPS as g, reducePoints as gt, RUNTIME_DEFAULTS as h, procedureAuthKey as ht, BatteryStatusSchema as i, sleep as in, kebabToCamel as it, bareAddonId as j, vectorStoreCapability as jt, authProviderCapability as k, userManagementCapability as kt, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as l, looseSchema as lt, REDACTED_SECRET as m, platformProbeCapability as mt, AlertSchema as n, resolveCapMount as nn, isSourceCap as nt, CORE_BLOCKS_ADDON_ID as o, localNetworkCapability as ot, METHOD_ACCESS_MAP as p, parseStreamParamsFormPatch as pt, enumerateSchemaFields as q, emitDownForOwnedCaps as qt, ApiKeyRecordSchema as r, scopeKey as rn, isVoidInput as rt, CORE_BLOCK_ADDON_PREFIX as s, logDestinationCapability as st, ALL_CAPABILITY_DEFINITIONS as t, readinessKey as tn, isSameAddonId as tt, DeclaredDevices as u, metricsProviderCapability as ut, STORAGE_ACCESS_FALLBACK as v, resolveMethodAuth as vt, UserRecordSchema as w, snapshotCapability as wt, StorageCleanupJobSchema as x, scopesAllowDeviceCap as xt, STREAM_PROFILE_META as y, runtimeStatePolicyFor as yt, decodeVectorBase64 as z, DeviceType as zt };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-Cek0wNdY.js");
3
- const require_dist = require("./dist-BhE8zNfY.js");
3
+ const require_dist = require("./dist-CFTKQGym.js");
4
4
  const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
5
5
  require("./builtins/alerts/index.js");
6
6
  const require_formatter = require("./formatter-DqAKDlvN.js");
@@ -26,7 +26,7 @@ require("./builtins/system-config/index.js");
26
26
  const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
27
27
  const require_file_data_plane = require("./file-data-plane-DO8KbxCe.js");
28
28
  const require_tls$1 = require("./tls-BxQlomxd.js");
29
- const require_manifest_system_deps = require("./manifest-system-deps-CJLqfJUs.js");
29
+ const require_manifest_system_deps = require("./manifest-system-deps-BIxY1Y5e.js");
30
30
  const require_resource_monitor = require("./resource-monitor-CdnzxBLP.js");
31
31
  const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
32
32
  let zod = require("zod");
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
2
- import { $ as isObjectInput, $t as parseJsonUnknown$1, Bt as ReadinessTimeoutError, Ft as DEVICE_STATUS_METHOD, Gt as createEvent, Ht as asJsonObject$1, J as extractNestedAddonId, Jt as expandCapMethods, Kt as emitDownForOwnedCaps, Nt as DATAPLANE_SECRET_HEADER$1, Pt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Q as isCollectionArrayMethod, Qt as parseJsonObject, T as addonSettingsCapability, Ut as asNumber, Wt as asString$1, Z as isArrayOutputSchema, _t as resolveMethodAuth, bt as scopesAllowDeviceCap, ct as looseSchema, dt as objectInputDeclaresAddonId, en as readinessKey, f as LOG_LEVEL_RANK, h as RUNTIME_DEFAULTS, in as EventCategory$1, it as lifecycleJobSchema, jt as errMsg$1, mt as procedureAuthKey, nn as scopeKey, nt as isVoidInput, p as METHOD_ACCESS_MAP, rt as kebabToCamel, st as logLevelAtMost, t as ALL_CAPABILITY_DEFINITIONS, tn as resolveCapMount, yt as scopesAllowAddon, zt as ReadinessRegistry } from "./dist-BpsHt11f.mjs";
2
+ import { $ as isCollectionArrayMethod, $t as parseJsonObject, Bt as ReadinessRegistry, E as addonSettingsCapability, Ft as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Gt as asString$1, It as DEVICE_STATUS_METHOD, Kt as createEvent, Mt as errMsg$1, Pt as DATAPLANE_SECRET_HEADER$1, Q as isArrayOutputSchema, Ut as asJsonObject$1, Vt as ReadinessTimeoutError, Wt as asNumber, Y as extractNestedAddonId, Yt as expandCapMethods, an as EventCategory$1, at as lifecycleJobSchema, bt as scopesAllowAddon, ct as logLevelAtMost, en as parseJsonUnknown$1, et as isObjectInput, f as LOG_LEVEL_RANK, ft as objectInputDeclaresAddonId, h as RUNTIME_DEFAULTS, ht as procedureAuthKey, it as kebabToCamel, lt as looseSchema, nn as resolveCapMount, p as METHOD_ACCESS_MAP, qt as emitDownForOwnedCaps, rn as scopeKey, rt as isVoidInput, t as ALL_CAPABILITY_DEFINITIONS, tn as readinessKey, vt as resolveMethodAuth, xt as scopesAllowDeviceCap } from "./dist-Dw9cm1NS.mjs";
3
3
  import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
4
4
  import "./builtins/alerts/index.mjs";
5
5
  import { t as formatLogLine } from "./formatter-B7qW8bPJ.mjs";
@@ -25,7 +25,7 @@ import "./builtins/system-config/index.mjs";
25
25
  import { WinstonDestination, WinstonLoggingAddon } from "./builtins/winston-logging/index.mjs";
26
26
  import { a as parseTokenizedUrl, c as collectModelFiles, d as downloadModel, f as ensureModel, h as isModelDownloaded, i as parseRangeHeader, l as deleteModelFromDisk, m as getModelFilePath, n as contentTypeFor, o as resolveFilePath, p as fetchJson, r as createAuthenticatedFileServer, s as ModelDownloadService, t as createFileDataPlaneHandler, u as downloadFile } from "./file-data-plane-BhKdxJgf.mjs";
27
27
  import { C as registerLanHttpHandler, S as readLanHttpState, _ as DEFAULT_LAN_HTTP_PORT, a as writeTlsMode, b as bindPendingLanHttp, c as loadTlsCert, d as collectCertIdentity, f as CA_VALIDITY_DAYS, g as evaluateExistingCert, h as SERVER_AUTH_OID, i as writeExtraSans, l as reissueTlsLeaf, m as MAX_LEAF_VALIDITY_DAYS, n as readTlsAccessStatus, o as validateUploadedTls, p as LEAF_RENEWAL_WINDOW_DAYS, r as readTlsMode, s as ensureTlsCert, t as readExtraSans, u as CA_COMMON_NAME, v as allFamiliesListenHost, x as closeLanHttp, y as applyLanHttp } from "./tls-DOTmtLCW.mjs";
28
- import { $ as FrameDecoder, $t as DECISIVE_HEAP_SPACES, A as createUdsEventBus, At as HEAP_WATCH_INTERVAL_MS, B as CapRouteError, Bt as buildHeapSample, C as ipcParentLink, Cn as diffEventPlane, Ct as resolveAddonClass, D as createHubCapForwardService, Dt as HEAP_RECLAIM_MIN_INTERVAL_MS, E as HUB_CAP_FWD_SERVICE, Et as createAddonDataPlaneFacility, F as LocalChildRegistry, Ft as RSS_BUDGET_REANNOUNCE_MIN_MS, G as PARENT_ROUTED_PROVIDER_ADDON_ID, Gt as hubMainRssBudget, H as callWithServiceDiscovery, Ht as createLoopDelayMeter, I as UDS_NO_ROUTE_PREFIX, It as RSS_BUDGET_RELEASE_RATIO, J as createLocalTransport, Jt as reclaimIntervalMs, K as __resetCapUsageRegistryForTests, Kt as nextRssBudgetState, L as AGENT_CAP_FWD_ACTION, Lt as RUNNER_HEAP_WATCH_INTERVAL_MS, M as createUdsLogger, Mt as HUB_MAIN_HEAP_WATCH_LABEL, N as createUdsLoggerWithControl, Nt as HUB_MAIN_RSS_BUDGET_MB, O as createParentUnownedCallHandler, Ot as HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS, P as LocalChildClient, Pt as HUB_RSS_BUDGET_ENV, Q as localEndpointPath, Qt as strandedMb, R as AGENT_CAP_FWD_SERVICE, Rt as RUNNER_RSS_BUDGET_ENV, S as buildLinkChain, Sn as createEventPlaneReader, St as installManifestNativeDeps, T as HUB_CAP_FWD_ACTION, Tt as runNpm, U as readMoleculerFanoutMode, Ut as createV8Reclaimer, V as classifyCapRoute, Vt as createDeferredHeapWatchSink, W as CapUsageRegistry, Wt as describeRss, X as UdsLocalTransportServer, Xt as startHeapWatch, Y as UdsLocalTransportClient, Yt as shouldReclaim, Z as SocketChannel, Zt as startRunnerHeapWatch, _ as AddonDepsManager, _n as sampleSocketDirection, _t as serializeTypedArrays, a as createUdsAddonContext, an as heapSpaceField, b as brokerCallForCap, bn as EVENT_PLANE_TOP_N, bt as CapabilityUnavailableError, c as getOrInitReadinessRegistryForClient, cn as EMPTY_SOCKET_PLANE_BASELINE, ct as createAddonService, d as clusterEventTopic, dn as createSocketPlaneReader, dt as capActionName, en as HEAP_SPACE_REPORT_MIN_MB, et as encodeFrame, f as getBrokerEventBus, fn as diffSocketPlane, ft as capActionSuffix, g as subscribePassthrough, gn as recordSocketFrame, gt as deserializeTypedArrays, h as setNodeEventInterest, hn as createSocketDirectionCounters, ht as parseCapAction, i as createAddonContext, in as heapSnapshotAuthorised, j as udsChildLogToWorkerEntry, jt as HEAP_WATCH_WARN_RATIO, k as createUdsEventBridge, kt as HEAP_RECLAIM_TRIGGER_MB, l as setHubConnected, ln as SOCKET_PLANE_TOP_N, lt as validateProviderRegistrations, m as registerEventBusService, mn as EMPTY_SOCKET_DIRECTION, mt as capServiceName, n as installManifestPythonDeps, nn as emitHeapDiagnosticReport, nt as buildUdsNativeCapProxy, o as getWorkerDeviceRegistry, on as readHeapSpaces, ot as mountNativeCapService, p as getMoleculerEventStats, pn as formatSocketPlane, pt as capBareAction, q as getCapUsageRegistry, qt as parseRssBudgetMb, r as adaptBrokerToCluster, rn as formatHeapSpaces, rt as createBrokerDeviceManagerApi, s as getOrInitReadinessRegistry, sn as selectReportedSpaces, t as installManifestSystemDeps, tn as RUNNER_HEAP_SNAPSHOT_ENV, tt as buildNativeCapProxy, u as EVENT_TOPIC_PREFIX, un as createSocketPlaneMeter, ut as NATIVE_PROVIDER_SERVICE_INFIX, v as createKernelHwAccel, vn as socketDirectionBytes, vt as DeviceRegistry, w as localProviderLink, wn as formatEventPlane, wt as resolveNpmInvocation, x as brokerTransportLink, xn as createEventPlaneMeter, xt as copyBundledNativeModules, y as resolveHwAccel, yn as socketDirectionMessages, yt as CapabilityHandle, z as CapRouteResolver, zt as ZERO_LOOP_DELAY } from "./manifest-system-deps-Bk_XLYbB.mjs";
28
+ import { $ as FrameDecoder, $t as DECISIVE_HEAP_SPACES, A as createUdsEventBus, At as HEAP_WATCH_INTERVAL_MS, B as CapRouteError, Bt as buildHeapSample, C as ipcParentLink, Cn as diffEventPlane, Ct as resolveAddonClass, D as createHubCapForwardService, Dt as HEAP_RECLAIM_MIN_INTERVAL_MS, E as HUB_CAP_FWD_SERVICE, Et as createAddonDataPlaneFacility, F as LocalChildRegistry, Ft as RSS_BUDGET_REANNOUNCE_MIN_MS, G as PARENT_ROUTED_PROVIDER_ADDON_ID, Gt as hubMainRssBudget, H as callWithServiceDiscovery, Ht as createLoopDelayMeter, I as UDS_NO_ROUTE_PREFIX, It as RSS_BUDGET_RELEASE_RATIO, J as createLocalTransport, Jt as reclaimIntervalMs, K as __resetCapUsageRegistryForTests, Kt as nextRssBudgetState, L as AGENT_CAP_FWD_ACTION, Lt as RUNNER_HEAP_WATCH_INTERVAL_MS, M as createUdsLogger, Mt as HUB_MAIN_HEAP_WATCH_LABEL, N as createUdsLoggerWithControl, Nt as HUB_MAIN_RSS_BUDGET_MB, O as createParentUnownedCallHandler, Ot as HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS, P as LocalChildClient, Pt as HUB_RSS_BUDGET_ENV, Q as localEndpointPath, Qt as strandedMb, R as AGENT_CAP_FWD_SERVICE, Rt as RUNNER_RSS_BUDGET_ENV, S as buildLinkChain, Sn as createEventPlaneReader, St as installManifestNativeDeps, T as HUB_CAP_FWD_ACTION, Tt as runNpm, U as readMoleculerFanoutMode, Ut as createV8Reclaimer, V as classifyCapRoute, Vt as createDeferredHeapWatchSink, W as CapUsageRegistry, Wt as describeRss, X as UdsLocalTransportServer, Xt as startHeapWatch, Y as UdsLocalTransportClient, Yt as shouldReclaim, Z as SocketChannel, Zt as startRunnerHeapWatch, _ as AddonDepsManager, _n as sampleSocketDirection, _t as serializeTypedArrays, a as createUdsAddonContext, an as heapSpaceField, b as brokerCallForCap, bn as EVENT_PLANE_TOP_N, bt as CapabilityUnavailableError, c as getOrInitReadinessRegistryForClient, cn as EMPTY_SOCKET_PLANE_BASELINE, ct as createAddonService, d as clusterEventTopic, dn as createSocketPlaneReader, dt as capActionName, en as HEAP_SPACE_REPORT_MIN_MB, et as encodeFrame, f as getBrokerEventBus, fn as diffSocketPlane, ft as capActionSuffix, g as subscribePassthrough, gn as recordSocketFrame, gt as deserializeTypedArrays, h as setNodeEventInterest, hn as createSocketDirectionCounters, ht as parseCapAction, i as createAddonContext, in as heapSnapshotAuthorised, j as udsChildLogToWorkerEntry, jt as HEAP_WATCH_WARN_RATIO, k as createUdsEventBridge, kt as HEAP_RECLAIM_TRIGGER_MB, l as setHubConnected, ln as SOCKET_PLANE_TOP_N, lt as validateProviderRegistrations, m as registerEventBusService, mn as EMPTY_SOCKET_DIRECTION, mt as capServiceName, n as installManifestPythonDeps, nn as emitHeapDiagnosticReport, nt as buildUdsNativeCapProxy, o as getWorkerDeviceRegistry, on as readHeapSpaces, ot as mountNativeCapService, p as getMoleculerEventStats, pn as formatSocketPlane, pt as capBareAction, q as getCapUsageRegistry, qt as parseRssBudgetMb, r as adaptBrokerToCluster, rn as formatHeapSpaces, rt as createBrokerDeviceManagerApi, s as getOrInitReadinessRegistry, sn as selectReportedSpaces, t as installManifestSystemDeps, tn as RUNNER_HEAP_SNAPSHOT_ENV, tt as buildNativeCapProxy, u as EVENT_TOPIC_PREFIX, un as createSocketPlaneMeter, ut as NATIVE_PROVIDER_SERVICE_INFIX, v as createKernelHwAccel, vn as socketDirectionBytes, vt as DeviceRegistry, w as localProviderLink, wn as formatEventPlane, wt as resolveNpmInvocation, x as brokerTransportLink, xn as createEventPlaneMeter, xt as copyBundledNativeModules, y as resolveHwAccel, yn as socketDirectionMessages, yt as CapabilityHandle, z as CapRouteResolver, zt as ZERO_LOOP_DELAY } from "./manifest-system-deps-DTz_zNQf.mjs";
29
29
  import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-BWmQ5i-o.mjs";
30
30
  import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
31
31
  import { z } from "zod";
@@ -1,12 +1,15 @@
1
1
  import { AddonDeclaration, IScopedLogger } from '@camstack/types';
2
- /** Host package managers this mechanism knows how to drive. */
3
- export type SystemPackageManager = 'apt' | 'apk' | 'dnf' | 'brew';
2
+ import { PackageInstallRequest, PackageInstallResult } from './system-package-broker.js';
3
+ import { SystemPackageManager } from './system-package-allowlist.js';
4
+ export type { SystemPackageManager } from './system-package-allowlist.js';
4
5
  /** Test seams — production callers omit these. */
5
6
  export interface InstallManifestSystemDepsOptions {
6
7
  readonly hasBinary?: (binary: string) => Promise<boolean>;
7
8
  readonly detectManager?: () => Promise<SystemPackageManager | null>;
8
9
  readonly run?: (command: string, args: readonly string[]) => Promise<void>;
9
10
  readonly platform?: NodeJS.Platform;
11
+ readonly helperAvailable?: () => Promise<boolean>;
12
+ readonly requestInstall?: (req: PackageInstallRequest) => Promise<PackageInstallResult>;
10
13
  }
11
14
  /**
12
15
  * Satisfy every `systemDependencies` entry the declaration carries.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Packages the privileged helper will install (D326).
3
+ *
4
+ * The helper process reads `scripts/docker/pkg-allowlist.json` (baked into
5
+ * the image). This module is the runner-side copy of the same list, so an
6
+ * unknown package is refused before a socket write. Keep them identical —
7
+ * `scripts/check-pkg-allowlist.ts` fails CI when they drift.
8
+ */
9
+ export type SystemPackageManager = 'apt' | 'apk' | 'dnf' | 'brew';
10
+ export type DistroPackageManager = Exclude<SystemPackageManager, 'brew'>;
11
+ export declare const DISTRO_PACKAGE_ALLOWLIST: Readonly<Record<DistroPackageManager, readonly string[]>>;
12
+ export declare function packageIsAllowlisted(manager: SystemPackageManager, packageName: string): boolean;
@@ -0,0 +1,31 @@
1
+ import { SystemPackageManager } from './system-package-allowlist.js';
2
+ export interface PackageInstallRequest {
3
+ readonly addonId: string;
4
+ readonly binary: string;
5
+ readonly manager: SystemPackageManager;
6
+ readonly packageName: string;
7
+ }
8
+ export interface PackageInstallResult {
9
+ readonly ok: boolean;
10
+ readonly error?: string;
11
+ }
12
+ export type PackageInstallDecision = {
13
+ readonly kind: 'helper';
14
+ } | {
15
+ readonly kind: 'local';
16
+ } | {
17
+ readonly kind: 'refuse';
18
+ readonly reason: 'not-allowlisted' | 'helper-unavailable';
19
+ };
20
+ /**
21
+ * Who is allowed to run the package manager for this request.
22
+ *
23
+ * Apt/apk/dnf need root. In the CamStack container that is the
24
+ * `camstack-pkgd` helper, not the runner and not hub-main (both uid
25
+ * 1001). Brew is owned by the logged-in user, so it stays in-process.
26
+ */
27
+ export declare function decidePackageInstall(input: {
28
+ readonly manager: SystemPackageManager;
29
+ readonly packageName: string;
30
+ readonly helperAvailable: boolean;
31
+ }): PackageInstallDecision;
@@ -0,0 +1,9 @@
1
+ import { PackageInstallRequest, PackageInstallResult } from './system-package-broker.js';
2
+ /** Default path the entrypoint binds before dropping to uid 1001. */
3
+ export declare const DEFAULT_PKGD_SOCKET = "/run/camstack/pkgd.sock";
4
+ export declare function pkgdSocketPath(): string;
5
+ export declare function privilegedHelperAvailable(socketPath?: string): boolean;
6
+ /**
7
+ * One JSON object per line. The helper answers one request per connection.
8
+ */
9
+ export declare function requestPrivilegedInstall(req: PackageInstallRequest, socketPath?: string, timeoutMs?: number): Promise<PackageInstallResult>;
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- require("./dist-BhE8zNfY.js");
2
+ require("./dist-CFTKQGym.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  node_crypto = require_chunk.__toESM(node_crypto);
5
5
  let _camstack_types_node = require("@camstack/types/node");
@@ -9698,6 +9698,106 @@ async function installManifestPythonDeps(declaration, addonDir, deps, logger) {
9698
9698
  await deps.installPythonRequirements(reqAbs);
9699
9699
  }
9700
9700
  //#endregion
9701
+ //#region src/kernel/deps/system-package-allowlist.ts
9702
+ var DISTRO_PACKAGE_ALLOWLIST = {
9703
+ apt: ["smbclient"],
9704
+ apk: ["samba-client"],
9705
+ dnf: ["samba-client"]
9706
+ };
9707
+ function packageIsAllowlisted(manager, packageName) {
9708
+ if (manager === "brew") return true;
9709
+ if (packageName.length === 0) return false;
9710
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9+._-]*$/.test(packageName)) return false;
9711
+ return DISTRO_PACKAGE_ALLOWLIST[manager].includes(packageName);
9712
+ }
9713
+ //#endregion
9714
+ //#region src/kernel/deps/system-package-broker.ts
9715
+ /**
9716
+ * Who is allowed to run the package manager for this request.
9717
+ *
9718
+ * Apt/apk/dnf need root. In the CamStack container that is the
9719
+ * `camstack-pkgd` helper, not the runner and not hub-main (both uid
9720
+ * 1001). Brew is owned by the logged-in user, so it stays in-process.
9721
+ */
9722
+ function decidePackageInstall(input) {
9723
+ if (input.manager === "brew") return { kind: "local" };
9724
+ if (!packageIsAllowlisted(input.manager, input.packageName)) return {
9725
+ kind: "refuse",
9726
+ reason: "not-allowlisted"
9727
+ };
9728
+ if (!input.helperAvailable) return {
9729
+ kind: "refuse",
9730
+ reason: "helper-unavailable"
9731
+ };
9732
+ return { kind: "helper" };
9733
+ }
9734
+ function pkgdSocketPath() {
9735
+ return process.env["CAMSTACK_PKGD_SOCKET"] ?? "/run/camstack/pkgd.sock";
9736
+ }
9737
+ function privilegedHelperAvailable(socketPath = pkgdSocketPath()) {
9738
+ return (0, node_fs.existsSync)(socketPath);
9739
+ }
9740
+ /**
9741
+ * One JSON object per line. The helper answers one request per connection.
9742
+ */
9743
+ function requestPrivilegedInstall(req, socketPath = pkgdSocketPath(), timeoutMs = 360 * 1e3) {
9744
+ return new Promise((resolve) => {
9745
+ const socket = (0, node_net.createConnection)({ path: socketPath });
9746
+ const chunks = [];
9747
+ const finish = (result) => {
9748
+ socket.destroy();
9749
+ resolve(result);
9750
+ };
9751
+ const timer = setTimeout(() => {
9752
+ finish({
9753
+ ok: false,
9754
+ error: `privileged helper timed out after ${timeoutMs}ms`
9755
+ });
9756
+ }, timeoutMs);
9757
+ socket.on("connect", () => {
9758
+ socket.write(`${JSON.stringify({
9759
+ v: 1,
9760
+ ...req
9761
+ })}\n`);
9762
+ });
9763
+ socket.on("data", (data) => {
9764
+ chunks.push(data);
9765
+ const text = Buffer.concat(chunks).toString("utf8");
9766
+ const nl = text.indexOf("\n");
9767
+ if (nl === -1) return;
9768
+ clearTimeout(timer);
9769
+ try {
9770
+ const parsed = JSON.parse(text.slice(0, nl));
9771
+ finish({
9772
+ ok: parsed.ok === true,
9773
+ ...parsed.error !== void 0 ? { error: parsed.error } : {}
9774
+ });
9775
+ } catch (err) {
9776
+ finish({
9777
+ ok: false,
9778
+ error: err instanceof Error ? err.message : String(err)
9779
+ });
9780
+ }
9781
+ });
9782
+ socket.on("error", (err) => {
9783
+ clearTimeout(timer);
9784
+ finish({
9785
+ ok: false,
9786
+ error: err.message
9787
+ });
9788
+ });
9789
+ socket.on("end", () => {
9790
+ if (chunks.length === 0) {
9791
+ clearTimeout(timer);
9792
+ finish({
9793
+ ok: false,
9794
+ error: "privileged helper closed without a reply"
9795
+ });
9796
+ }
9797
+ });
9798
+ });
9799
+ }
9800
+ //#endregion
9701
9801
  //#region src/kernel/deps/manifest-system-deps.ts
9702
9802
  /**
9703
9803
  * Auto-install the host binaries declared in an addon's manifest
@@ -9728,6 +9828,9 @@ async function installManifestPythonDeps(declaration, addonDir, deps, logger) {
9728
9828
  * 4. **Platform reality is stated, not assumed.** An unsupported host logs
9729
9829
  * which manager it looked for and continues. Silence would read as
9730
9830
  * "installed".
9831
+ * 5. **Apt is not the runner's.** Distro package managers need root. The
9832
+ * runner and hub-main are uid 1001 (`gosu` in the entrypoint). Apt/apk/dnf
9833
+ * go through `camstack-pkgd` (allowlisted). Brew stays in-process.
9731
9834
  *
9732
9835
  * Every branch that declines to install SAYS SO. A dependency step that
9733
9836
  * produced no line at all is indistinguishable from one that never ran, and
@@ -9750,12 +9853,16 @@ async function installManifestSystemDeps(declaration, logger, options = {}) {
9750
9853
  const detectManager = options.detectManager ?? defaultDetectManager;
9751
9854
  const run = options.run ?? defaultRun;
9752
9855
  const platform = options.platform ?? process.platform;
9856
+ const helperAvailable = options.helperAvailable ?? (async () => privilegedHelperAvailable());
9857
+ const requestInstall = options.requestInstall ?? ((req) => requestPrivilegedInstall(req));
9753
9858
  for (const dep of deps) try {
9754
9859
  await satisfyOne(dep, declaration.id, {
9755
9860
  hasBinary,
9756
9861
  detectManager,
9757
9862
  run,
9758
- platform
9863
+ platform,
9864
+ helperAvailable,
9865
+ requestInstall
9759
9866
  }, logger);
9760
9867
  } catch (err) {
9761
9868
  logger.warn("system dependency step failed", { meta: {
@@ -9793,15 +9900,43 @@ async function satisfyOne(dep, addonId, rt, logger) {
9793
9900
  } });
9794
9901
  return;
9795
9902
  }
9796
- const plan = planFor(manager, packageName);
9903
+ const decision = decidePackageInstall({
9904
+ manager,
9905
+ packageName,
9906
+ helperAvailable: await rt.helperAvailable()
9907
+ });
9908
+ if (decision.kind === "refuse") {
9909
+ const message = decision.reason === "helper-unavailable" ? "system dependency missing and the privileged helper is not running — apt cannot run as uid 1001" : "system dependency missing and the package is not on the helper allowlist";
9910
+ logger.warn(message, { meta: {
9911
+ addonId,
9912
+ binary: dep.binary,
9913
+ manager,
9914
+ package: packageName,
9915
+ reason: decision.reason,
9916
+ ...dep.reason !== void 0 ? { reason: dep.reason } : {}
9917
+ } });
9918
+ return;
9919
+ }
9797
9920
  logger.info("installing system dependency", { meta: {
9798
9921
  addonId,
9799
9922
  binary: dep.binary,
9800
9923
  manager,
9801
- package: packageName
9924
+ package: packageName,
9925
+ via: decision.kind
9802
9926
  } });
9803
9927
  try {
9804
- for (const [command, args] of plan.steps) await rt.run(command, args);
9928
+ if (decision.kind === "helper") {
9929
+ const result = await rt.requestInstall({
9930
+ addonId,
9931
+ binary: dep.binary,
9932
+ manager,
9933
+ packageName
9934
+ });
9935
+ if (!result.ok) throw new Error(result.error ?? "privileged helper refused");
9936
+ } else {
9937
+ const plan = planFor(manager, packageName);
9938
+ for (const [command, args] of plan.steps) await rt.run(command, args);
9939
+ }
9805
9940
  } catch (err) {
9806
9941
  logger.warn("system dependency install failed — the addon loads, its capability must refuse", { meta: {
9807
9942
  addonId,