@homeflare/alchemy 0.31.2 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +39 -3
  2. package/dist/linux/container-form.d.ts +129 -0
  3. package/dist/linux/container-form.d.ts.map +1 -0
  4. package/dist/linux/container-generator.d.ts +74 -0
  5. package/dist/linux/container-generator.d.ts.map +1 -0
  6. package/dist/linux/container-handlers.d.ts +15 -0
  7. package/dist/linux/container-handlers.d.ts.map +1 -0
  8. package/dist/linux/container-lifecycle.d.ts +37 -0
  9. package/dist/linux/container-lifecycle.d.ts.map +1 -0
  10. package/dist/linux/container-preflight.d.ts +34 -0
  11. package/dist/linux/container-preflight.d.ts.map +1 -0
  12. package/dist/linux/container-secrets.d.ts +37 -0
  13. package/dist/linux/container-secrets.d.ts.map +1 -0
  14. package/dist/linux/container-settle.d.ts +34 -0
  15. package/dist/linux/container-settle.d.ts.map +1 -0
  16. package/dist/linux/container.d.ts +30 -0
  17. package/dist/linux/container.d.ts.map +1 -0
  18. package/dist/linux/fake-quadlet.d.ts +25 -0
  19. package/dist/linux/fake-quadlet.d.ts.map +1 -0
  20. package/dist/linux/index.d.ts +6 -3
  21. package/dist/linux/index.d.ts.map +1 -1
  22. package/dist/linux/index.js +641 -268
  23. package/dist/linux/index.js.map +15 -7
  24. package/dist/linux/providers.d.ts +1 -1
  25. package/dist/linux/providers.d.ts.map +1 -1
  26. package/dist/linux/systemctl.d.ts +7 -1
  27. package/dist/linux/systemctl.d.ts.map +1 -1
  28. package/dist/opnsense/alias-form.d.ts +29 -0
  29. package/dist/opnsense/alias-form.d.ts.map +1 -0
  30. package/dist/opnsense/alias.d.ts +81 -0
  31. package/dist/opnsense/alias.d.ts.map +1 -0
  32. package/dist/opnsense/category-form.d.ts +10 -0
  33. package/dist/opnsense/category-form.d.ts.map +1 -0
  34. package/dist/opnsense/category.d.ts +58 -0
  35. package/dist/opnsense/category.d.ts.map +1 -0
  36. package/dist/opnsense/credentials.d.ts +36 -0
  37. package/dist/opnsense/credentials.d.ts.map +1 -0
  38. package/dist/opnsense/fake-opnsense.d.ts +51 -0
  39. package/dist/opnsense/fake-opnsense.d.ts.map +1 -0
  40. package/dist/opnsense/group-form.d.ts +11 -0
  41. package/dist/opnsense/group-form.d.ts.map +1 -0
  42. package/dist/opnsense/group.d.ts +62 -0
  43. package/dist/opnsense/group.d.ts.map +1 -0
  44. package/dist/opnsense/index.d.ts +16 -0
  45. package/dist/opnsense/index.d.ts.map +1 -0
  46. package/dist/opnsense/index.js +211 -0
  47. package/dist/opnsense/index.js.map +20 -0
  48. package/dist/opnsense/policy.d.ts +20 -0
  49. package/dist/opnsense/policy.d.ts.map +1 -0
  50. package/dist/opnsense/providers.d.ts +13 -0
  51. package/dist/opnsense/providers.d.ts.map +1 -0
  52. package/dist/opnsense/resource.d.ts +74 -0
  53. package/dist/opnsense/resource.d.ts.map +1 -0
  54. package/dist/opnsense/wire.d.ts +39 -0
  55. package/dist/opnsense/wire.d.ts.map +1 -0
  56. package/dist/proxmox/index.js +106 -47
  57. package/dist/proxmox/index.js.map +6 -4
  58. package/dist/proxmox/storage-form.d.ts +54 -0
  59. package/dist/proxmox/storage-form.d.ts.map +1 -0
  60. package/dist/proxmox/storage-wire.d.ts +56 -0
  61. package/dist/proxmox/storage-wire.d.ts.map +1 -0
  62. package/dist/proxmox/storage.d.ts +55 -60
  63. package/dist/proxmox/storage.d.ts.map +1 -1
  64. package/dist/unifi/fake-unifi.d.ts +48 -0
  65. package/dist/unifi/fake-unifi.d.ts.map +1 -0
  66. package/dist/unifi/firewall-zone-form.d.ts +40 -0
  67. package/dist/unifi/firewall-zone-form.d.ts.map +1 -0
  68. package/dist/unifi/firewall-zone.d.ts +50 -0
  69. package/dist/unifi/firewall-zone.d.ts.map +1 -0
  70. package/dist/unifi/index.d.ts +13 -0
  71. package/dist/unifi/index.d.ts.map +1 -0
  72. package/dist/unifi/index.js +190 -0
  73. package/dist/unifi/index.js.map +16 -0
  74. package/dist/unifi/network-form.d.ts +67 -0
  75. package/dist/unifi/network-form.d.ts.map +1 -0
  76. package/dist/unifi/network.d.ts +67 -0
  77. package/dist/unifi/network.d.ts.map +1 -0
  78. package/dist/unifi/policy.d.ts +20 -0
  79. package/dist/unifi/policy.d.ts.map +1 -0
  80. package/dist/unifi/providers.d.ts +13 -0
  81. package/dist/unifi/providers.d.ts.map +1 -0
  82. package/dist/unifi/resource.d.ts +64 -0
  83. package/dist/unifi/resource.d.ts.map +1 -0
  84. package/docs/opnsense.md +146 -0
  85. package/docs/provider-standard.md +1 -1
  86. package/docs/quadlet-container.md +132 -0
  87. package/docs/unifi.md +93 -0
  88. package/package.json +12 -2
  89. package/src/linux/container-fixture.test.ts +92 -0
  90. package/src/linux/container-form.ts +243 -0
  91. package/src/linux/container-generator.test.ts +195 -0
  92. package/src/linux/container-generator.ts +113 -0
  93. package/src/linux/container-handlers.ts +73 -0
  94. package/src/linux/container-lifecycle.test.ts +209 -0
  95. package/src/linux/container-lifecycle.ts +217 -0
  96. package/src/linux/container-preflight.ts +97 -0
  97. package/src/linux/container-secrets.test.ts +171 -0
  98. package/src/linux/container-secrets.ts +112 -0
  99. package/src/linux/container-settle.ts +97 -0
  100. package/src/linux/container.ts +60 -0
  101. package/src/linux/fake-quadlet.ts +127 -0
  102. package/src/linux/index.ts +11 -3
  103. package/src/linux/providers.ts +2 -0
  104. package/src/linux/systemctl.ts +9 -0
  105. package/src/opnsense/alias-form.test.ts +89 -0
  106. package/src/opnsense/alias-form.ts +53 -0
  107. package/src/opnsense/alias.test.ts +203 -0
  108. package/src/opnsense/alias.ts +117 -0
  109. package/src/opnsense/category-form.test.ts +54 -0
  110. package/src/opnsense/category-form.ts +20 -0
  111. package/src/opnsense/category.test.ts +138 -0
  112. package/src/opnsense/category.ts +82 -0
  113. package/src/opnsense/credentials.ts +41 -0
  114. package/src/opnsense/fake-opnsense.ts +79 -0
  115. package/src/opnsense/group-form.test.ts +75 -0
  116. package/src/opnsense/group-form.ts +25 -0
  117. package/src/opnsense/group.test.ts +141 -0
  118. package/src/opnsense/group.ts +78 -0
  119. package/src/opnsense/index.ts +45 -0
  120. package/src/opnsense/policy.ts +49 -0
  121. package/src/opnsense/providers.ts +21 -0
  122. package/src/opnsense/resource.ts +146 -0
  123. package/src/opnsense/wire.ts +56 -0
  124. package/src/opnsense/write-refusal.test.ts +148 -0
  125. package/src/proxmox/storage-form.ts +144 -0
  126. package/src/proxmox/storage-read-failure.test.ts +214 -0
  127. package/src/proxmox/storage-wire.ts +124 -0
  128. package/src/proxmox/storage.ts +165 -175
  129. package/src/unifi/fake-unifi.ts +60 -0
  130. package/src/unifi/firewall-zone-form.ts +65 -0
  131. package/src/unifi/firewall-zone.test.ts +88 -0
  132. package/src/unifi/firewall-zone.ts +66 -0
  133. package/src/unifi/index.ts +26 -0
  134. package/src/unifi/network-form.ts +207 -0
  135. package/src/unifi/network.test.ts +209 -0
  136. package/src/unifi/network.ts +83 -0
  137. package/src/unifi/policy.ts +37 -0
  138. package/src/unifi/providers.ts +15 -0
  139. package/src/unifi/resource.test.ts +133 -0
  140. package/src/unifi/resource.ts +131 -0
@@ -5130,64 +5130,123 @@ var handlers24 = pveHandlers({
5130
5130
  var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect63.succeed(ProxmoxSdnZone.Provider.of(handlers24)));
5131
5131
  // src/proxmox/storage.ts
5132
5132
  import { Resource as Resource34 } from "alchemy";
5133
+ import { isResolved as isResolved15 } from "alchemy/Diff";
5133
5134
  import * as Provider34 from "alchemy/Provider";
5134
- import * as Effect64 from "effect/Effect";
5135
- var ProxmoxStorage = Resource34("Proxmox.Storage", {
5136
- defaultRemovalPolicy: "retain"
5137
- });
5138
- var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
5135
+ import * as storage2 from "@distilled.cloud/proxmox/storage";
5136
+ import * as Effect65 from "effect/Effect";
5137
+
5138
+ // src/proxmox/storage-form.ts
5139
+ var STORAGE_CREATE = "pve:POST /storage";
5140
+ var STORAGE_UPDATE = "pve:PUT /storage/{storage}";
5139
5141
  var field6 = (name, value) => value === undefined ? {} : { [name]: value };
5140
5142
  var locatorForm = (locator) => ({ ...locator });
5141
- var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
5142
- var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
5143
- var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
5143
+ var underscored = (form) => Object.fromEntries(Object.entries(form).map(([key, value]) => [key.replaceAll("-", "_"), value]));
5144
5144
  var mutable2 = (props) => ({
5145
5145
  ...field6("comment", props.comment),
5146
5146
  ...field6("content", props.content),
5147
5147
  ...field6("disable", flag(props.disable)),
5148
- ...field6("maxfiles", props.maxfiles === undefined ? undefined : String(props.maxfiles)),
5149
5148
  ...field6("nodes", props.nodes),
5150
5149
  ...field6("preallocation", props.preallocation),
5151
5150
  ...field6("prune-backups", props["prune-backups"]),
5152
5151
  ...field6("shared", flag(props.shared))
5153
5152
  });
5154
- var handlers25 = pveHandlers({
5155
- readRole: "provision",
5156
- attributes: (live, props) => ({
5157
- comment: str2(live["comment"]),
5158
- content: str2(live["content"]),
5159
- disable: bool(live["disable"]),
5160
- maxfiles: typeof live["maxfiles"] === "number" ? live["maxfiles"] : -1,
5161
- nodes: str2(live["nodes"]),
5162
- preallocation: str2(live["preallocation"]),
5163
- "prune-backups": str2(live["prune-backups"]),
5164
- shared: bool(live["shared"]),
5153
+ var createForm10 = (props) => ({
5154
+ ...locatorForm(props.locator),
5155
+ ...mutable2(props),
5156
+ storage: props.storage,
5157
+ type: props.type
5158
+ });
5159
+ var updateForm7 = (props) => ({
5160
+ ...mutable2(props),
5161
+ storage: props.storage
5162
+ });
5163
+ var toDistilledCreate = (props) => underscored(createForm10(props));
5164
+ var toDistilledUpdate = (props) => underscored(updateForm7(props));
5165
+
5166
+ // src/proxmox/storage-wire.ts
5167
+ import * as storage from "@distilled.cloud/proxmox/storage";
5168
+ import * as Effect64 from "effect/Effect";
5169
+ var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
5170
+ var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
5171
+ var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
5172
+ var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
5173
+ var attributesOf7 = (live, props) => {
5174
+ const data = live;
5175
+ return {
5176
+ comment: str2(data["comment"]),
5177
+ content: str2(data["content"]),
5178
+ disable: bool(data["disable"]),
5179
+ nodes: str2(data["nodes"]),
5180
+ preallocation: str2(data["preallocation"]),
5181
+ "prune-backups": str2(data["prune-backups"]),
5182
+ shared: bool(data["shared"]),
5165
5183
  storage: props.storage,
5166
- type: str2(live["type"], props.type)
5184
+ type: str2(data["type"], props.type)
5185
+ };
5186
+ };
5187
+ var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect64.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf7(live, props)));
5188
+ var readStorage = (props) => readStorageOrFail(props).pipe(Effect64.orElseSucceed(() => {
5189
+ return;
5190
+ }));
5191
+ var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
5192
+ var matches7 = (attributes2, props) => sameList2(props.content, attributes2.content) && sameList2(props.nodes, attributes2.nodes) && sameList2(props["prune-backups"], attributes2["prune-backups"]) && same7(props.disable, attributes2.disable) && same7(props.shared, attributes2.shared) && same7(props.preallocation, attributes2.preallocation) && same7(props.comment, attributes2.comment);
5193
+
5194
+ // src/proxmox/storage.ts
5195
+ var ProxmoxStorage = Resource34("Proxmox.Storage", {
5196
+ defaultRemovalPolicy: "retain"
5197
+ });
5198
+ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect65.succeed(ProxmoxStorage.Provider.of({
5199
+ list: () => Effect65.succeed([]),
5200
+ read: Effect65.fn(function* ({ olds, output }) {
5201
+ return dropUnreadable6(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
5167
5202
  }),
5168
- collection: () => "storage",
5169
- createForm: (props) => ({
5170
- ...locatorForm(props.locator),
5171
- ...mutable2(props),
5172
- storage: props.storage,
5173
- type: props.type
5203
+ diff: Effect65.fn(function* ({ news, output }) {
5204
+ if (!isResolved15(news))
5205
+ return;
5206
+ yield* guardWrite2(STORAGE_CREATE, createForm10(news), output === undefined);
5207
+ yield* guardWrite2(STORAGE_UPDATE, updateForm7(news), false);
5208
+ if (output === undefined)
5209
+ return;
5210
+ const live = yield* readStorageOrFail(news);
5211
+ if (live === UNREADABLE) {
5212
+ yield* unreadableWarning("Proxmox.Storage", news.storage);
5213
+ return { action: "noop" };
5214
+ }
5215
+ if (live === undefined) {
5216
+ yield* guardWrite2(STORAGE_CREATE, createForm10(news), true);
5217
+ return { action: "update" };
5218
+ }
5219
+ return matches7(live, news) ? { action: "noop" } : { action: "update" };
5174
5220
  }),
5175
- endpoint: { create: "pve:POST /storage", update: "pve:PUT /storage/{storage}" },
5176
- matches: (attributes2, props) => sameList2(props.content, attributes2.content) && sameList2(props.nodes, attributes2.nodes) && sameList2(props["prune-backups"], attributes2["prune-backups"]) && same7(props.disable, attributes2.disable) && same7(props.shared, attributes2.shared) && same7(props.preallocation, attributes2.preallocation) && same7(props.comment, attributes2.comment) && same7(props.maxfiles, attributes2.maxfiles),
5177
- path: (props) => `storage/${props.storage}`,
5178
- updateForm: mutable2
5179
- });
5180
- var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect64.succeed(ProxmoxStorage.Provider.of(handlers25)));
5221
+ reconcile: Effect65.fn(function* ({ news }) {
5222
+ const before = dropUnreadable6(yield* readStorage(news));
5223
+ yield* guardWrite2(STORAGE_CREATE, createForm10(news), before === undefined);
5224
+ yield* guardWrite2(STORAGE_UPDATE, updateForm7(news), false);
5225
+ if (before === undefined) {
5226
+ yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate(news)));
5227
+ } else if (!matches7(before, news)) {
5228
+ yield* runPve(news.target, "provision", true, storage2.putStorage(toDistilledUpdate(news)));
5229
+ }
5230
+ const after = dropUnreadable6(yield* readStorage(news));
5231
+ if (after === undefined) {
5232
+ return yield* Effect65.die(new Error(`storage/${news.storage}: the write returned no error but the storage is still ` + 'absent. PVE wraps every answer in {"data":...} and can report success on a ' + "call that did nothing -- read back rather than trusting the status code."));
5233
+ }
5234
+ return after;
5235
+ }),
5236
+ delete: Effect65.fn(function* ({ olds }) {
5237
+ yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
5238
+ })
5239
+ })));
5181
5240
  // src/proxmox/zfs-pool.ts
5182
5241
  import { Resource as Resource35 } from "alchemy";
5183
5242
  import * as Provider35 from "alchemy/Provider";
5184
- import * as Effect66 from "effect/Effect";
5243
+ import * as Effect67 from "effect/Effect";
5185
5244
 
5186
5245
  // src/proxmox/zfs-pool-write.ts
5187
- import * as Effect65 from "effect/Effect";
5246
+ import * as Effect66 from "effect/Effect";
5188
5247
  var ZFS_POOL_ENDPOINT = { create: "pve:POST /nodes/{node}/disks/zfs" };
5189
5248
  var zfsPoolEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? {} : ZFS_POOL_ENDPOINT;
5190
- var createForm10 = (props) => ({
5249
+ var createForm11 = (props) => ({
5191
5250
  ...props.devices === undefined ? {} : { devices: props.devices.join(",") },
5192
5251
  name: props.name,
5193
5252
  ...props.raidlevel === undefined ? {} : { raidlevel: props.raidlevel },
@@ -5196,24 +5255,24 @@ var createForm10 = (props) => ({
5196
5255
  ...props["draid-config"] === undefined ? {} : { "draid-config": props["draid-config"] }
5197
5256
  });
5198
5257
  var SETTLE_ATTEMPTS = 30;
5199
- var createPool = (props, collection2, path2, read4) => Effect65.gen(function* () {
5258
+ var createPool = (props, collection2, path2, read4) => Effect66.gen(function* () {
5200
5259
  const existing = yield* read4(props);
5201
5260
  if (existing !== undefined)
5202
5261
  return existing;
5203
5262
  if (props.devices === undefined || props.raidlevel === undefined) {
5204
- return yield* Effect65.die(new Error(`${props.node}/${props.name}: this is an adopt-only declaration (no \`devices\` or ` + "`raidlevel`) and the pool is not there to adopt. An adopt-only Proxmox.ZfsPool never " + "creates -- declare both fields for a pool this resource should build, or point this " + "declaration at a pool that already exists on this node."));
5263
+ return yield* Effect66.die(new Error(`${props.node}/${props.name}: this is an adopt-only declaration (no \`devices\` or ` + "`raidlevel`) and the pool is not there to adopt. An adopt-only Proxmox.ZfsPool never " + "creates -- declare both fields for a pool this resource should build, or point this " + "declaration at a pool that already exists on this node."));
5205
5264
  }
5206
- const upid = yield* pve(props.target, "provision", "POST", collection2, createForm10(props));
5207
- const settle4 = (attempts) => Effect65.gen(function* () {
5265
+ const upid = yield* pve(props.target, "provision", "POST", collection2, createForm11(props));
5266
+ const settle4 = (attempts) => Effect66.gen(function* () {
5208
5267
  const live = yield* read4(props);
5209
5268
  if (live !== undefined || attempts <= 0)
5210
5269
  return live;
5211
- yield* Effect65.sleep("2 seconds");
5270
+ yield* Effect66.sleep("2 seconds");
5212
5271
  return yield* settle4(attempts - 1);
5213
5272
  });
5214
5273
  const after = yield* settle4(SETTLE_ATTEMPTS);
5215
5274
  if (after === undefined) {
5216
- return yield* Effect65.die(new Error(`${path2}: POST returned ${text(upid, "(no UPID)")} but the pool has not appeared. That ` + "POST only forks a `zfscreate` worker, so the task holds the real error -- read it " + `with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. NOTHING WAS RETRIED AND ` + "NOTHING WAS CLEANED UP: if the worker reached `zpool create`, the declared devices " + "have already been written to."));
5275
+ return yield* Effect66.die(new Error(`${path2}: POST returned ${text(upid, "(no UPID)")} but the pool has not appeared. That ` + "POST only forks a `zfscreate` worker, so the task holds the real error -- read it " + `with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. NOTHING WAS RETRIED AND ` + "NOTHING WAS CLEANED UP: if the worker reached `zpool create`, the declared devices " + "have already been written to."));
5217
5276
  }
5218
5277
  return after;
5219
5278
  });
@@ -5238,7 +5297,7 @@ var spec2 = {
5238
5297
  };
5239
5298
  },
5240
5299
  collection: (props) => `nodes/${props.node}/disks/zfs`,
5241
- createForm: createForm10,
5300
+ createForm: createForm11,
5242
5301
  endpoint: zfsPoolEndpoint,
5243
5302
  matches: () => true,
5244
5303
  path: (props) => `nodes/${props.node}/disks/zfs/${props.name}`
@@ -5249,14 +5308,14 @@ var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
5249
5308
  defaultRemovalPolicy: "retain"
5250
5309
  });
5251
5310
  var ops3 = pveOperations(spec2);
5252
- var handlers26 = {
5311
+ var handlers25 = {
5253
5312
  ...pveHandlers(spec2),
5254
- delete: Effect66.fn(function* ({ olds }) {
5313
+ delete: Effect67.fn(function* ({ olds }) {
5255
5314
  yield* destroyPool(olds, spec2.path(olds));
5256
5315
  }),
5257
5316
  reconcile: ({ news }) => createPool(news, spec2.collection(news), spec2.path(news), ops3.read)
5258
5317
  };
5259
- var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect66.succeed(ProxmoxZfsPool.Provider.of(handlers26)));
5318
+ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect67.succeed(ProxmoxZfsPool.Provider.of(handlers25)));
5260
5319
  export {
5261
5320
  PROVISION_DEFAULTS,
5262
5321
  PROVISION_PRIVILEGES,
@@ -5333,5 +5392,5 @@ export {
5333
5392
  violations
5334
5393
  };
5335
5394
 
5336
- //# debugId=E83D3C3771546F7064756E2164756E21
5395
+ //# debugId=1F128D1971E713E364756E2164756E21
5337
5396
  //# sourceMappingURL=index.js.map