@intentic/providers 1.18.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 (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/dist/app.d.ts +4 -0
  4. package/dist/app.d.ts.map +1 -0
  5. package/dist/app.js +72 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/authentik-api.d.ts +23 -0
  8. package/dist/authentik-api.d.ts.map +1 -0
  9. package/dist/authentik-api.js +67 -0
  10. package/dist/authentik-api.js.map +1 -0
  11. package/dist/authentik-client.d.ts +4 -0
  12. package/dist/authentik-client.d.ts.map +1 -0
  13. package/dist/authentik-client.js +50 -0
  14. package/dist/authentik-client.js.map +1 -0
  15. package/dist/authentik.d.ts +4 -0
  16. package/dist/authentik.d.ts.map +1 -0
  17. package/dist/authentik.js +132 -0
  18. package/dist/authentik.js.map +1 -0
  19. package/dist/backing-ssh.d.ts +8 -0
  20. package/dist/backing-ssh.d.ts.map +1 -0
  21. package/dist/backing-ssh.js +44 -0
  22. package/dist/backing-ssh.js.map +1 -0
  23. package/dist/backup-restore.d.ts +15 -0
  24. package/dist/backup-restore.d.ts.map +1 -0
  25. package/dist/backup-restore.js +49 -0
  26. package/dist/backup-restore.js.map +1 -0
  27. package/dist/backup.d.ts +4 -0
  28. package/dist/backup.d.ts.map +1 -0
  29. package/dist/backup.js +150 -0
  30. package/dist/backup.js.map +1 -0
  31. package/dist/cf-route.d.ts +5 -0
  32. package/dist/cf-route.d.ts.map +1 -0
  33. package/dist/cf-route.js +74 -0
  34. package/dist/cf-route.js.map +1 -0
  35. package/dist/ci.d.ts +4 -0
  36. package/dist/ci.d.ts.map +1 -0
  37. package/dist/ci.js +151 -0
  38. package/dist/ci.js.map +1 -0
  39. package/dist/cloudflare-api.d.ts +85 -0
  40. package/dist/cloudflare-api.d.ts.map +1 -0
  41. package/dist/cloudflare-api.js +110 -0
  42. package/dist/cloudflare-api.js.map +1 -0
  43. package/dist/cloudflare.d.ts +4 -0
  44. package/dist/cloudflare.d.ts.map +1 -0
  45. package/dist/cloudflare.js +29 -0
  46. package/dist/cloudflare.js.map +1 -0
  47. package/dist/deploy-hook.d.ts +4 -0
  48. package/dist/deploy-hook.d.ts.map +1 -0
  49. package/dist/deploy-hook.js +79 -0
  50. package/dist/deploy-hook.js.map +1 -0
  51. package/dist/deployment.d.ts +4 -0
  52. package/dist/deployment.d.ts.map +1 -0
  53. package/dist/deployment.js +103 -0
  54. package/dist/deployment.js.map +1 -0
  55. package/dist/discord-api.d.ts +31 -0
  56. package/dist/discord-api.d.ts.map +1 -0
  57. package/dist/discord-api.js +85 -0
  58. package/dist/discord-api.js.map +1 -0
  59. package/dist/discord.d.ts +4 -0
  60. package/dist/discord.d.ts.map +1 -0
  61. package/dist/discord.js +133 -0
  62. package/dist/discord.js.map +1 -0
  63. package/dist/forgejo-api.d.ts +209 -0
  64. package/dist/forgejo-api.d.ts.map +1 -0
  65. package/dist/forgejo-api.fake.d.ts +3 -0
  66. package/dist/forgejo-api.fake.d.ts.map +1 -0
  67. package/dist/forgejo-api.fake.js +31 -0
  68. package/dist/forgejo-api.fake.js.map +1 -0
  69. package/dist/forgejo-api.js +181 -0
  70. package/dist/forgejo-api.js.map +1 -0
  71. package/dist/forgejo-notify.d.ts +4 -0
  72. package/dist/forgejo-notify.d.ts.map +1 -0
  73. package/dist/forgejo-notify.js +103 -0
  74. package/dist/forgejo-notify.js.map +1 -0
  75. package/dist/forgejo-org.d.ts +4 -0
  76. package/dist/forgejo-org.d.ts.map +1 -0
  77. package/dist/forgejo-org.js +43 -0
  78. package/dist/forgejo-org.js.map +1 -0
  79. package/dist/forgejo-runner.d.ts +4 -0
  80. package/dist/forgejo-runner.d.ts.map +1 -0
  81. package/dist/forgejo-runner.js +111 -0
  82. package/dist/forgejo-runner.js.map +1 -0
  83. package/dist/forgejo-team.d.ts +4 -0
  84. package/dist/forgejo-team.d.ts.map +1 -0
  85. package/dist/forgejo-team.js +68 -0
  86. package/dist/forgejo-team.js.map +1 -0
  87. package/dist/forgejo-user.d.ts +4 -0
  88. package/dist/forgejo-user.d.ts.map +1 -0
  89. package/dist/forgejo-user.js +50 -0
  90. package/dist/forgejo-user.js.map +1 -0
  91. package/dist/forgejo.d.ts +4 -0
  92. package/dist/forgejo.d.ts.map +1 -0
  93. package/dist/forgejo.js +169 -0
  94. package/dist/forgejo.js.map +1 -0
  95. package/dist/garage-bucket.d.ts +4 -0
  96. package/dist/garage-bucket.d.ts.map +1 -0
  97. package/dist/garage-bucket.js +92 -0
  98. package/dist/garage-bucket.js.map +1 -0
  99. package/dist/garage.d.ts +4 -0
  100. package/dist/garage.d.ts.map +1 -0
  101. package/dist/garage.js +124 -0
  102. package/dist/garage.js.map +1 -0
  103. package/dist/gh-ci.d.ts +4 -0
  104. package/dist/gh-ci.d.ts.map +1 -0
  105. package/dist/gh-ci.js +153 -0
  106. package/dist/gh-ci.js.map +1 -0
  107. package/dist/gh-deployment.d.ts +4 -0
  108. package/dist/gh-deployment.d.ts.map +1 -0
  109. package/dist/gh-deployment.js +92 -0
  110. package/dist/gh-deployment.js.map +1 -0
  111. package/dist/gh-repo.d.ts +4 -0
  112. package/dist/gh-repo.d.ts.map +1 -0
  113. package/dist/gh-repo.js +52 -0
  114. package/dist/gh-repo.js.map +1 -0
  115. package/dist/github-api.d.ts +70 -0
  116. package/dist/github-api.d.ts.map +1 -0
  117. package/dist/github-api.js +120 -0
  118. package/dist/github-api.js.map +1 -0
  119. package/dist/github.d.ts +4 -0
  120. package/dist/github.d.ts.map +1 -0
  121. package/dist/github.js +34 -0
  122. package/dist/github.js.map +1 -0
  123. package/dist/guarded-update.d.ts +14 -0
  124. package/dist/guarded-update.d.ts.map +1 -0
  125. package/dist/guarded-update.js +25 -0
  126. package/dist/guarded-update.js.map +1 -0
  127. package/dist/host.d.ts +4 -0
  128. package/dist/host.d.ts.map +1 -0
  129. package/dist/host.js +48 -0
  130. package/dist/host.js.map +1 -0
  131. package/dist/index.d.ts +42 -0
  132. package/dist/index.d.ts.map +1 -0
  133. package/dist/index.js +35 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/inputs.d.ts +23 -0
  136. package/dist/inputs.d.ts.map +1 -0
  137. package/dist/inputs.js +34 -0
  138. package/dist/inputs.js.map +1 -0
  139. package/dist/komodo-api.d.ts +150 -0
  140. package/dist/komodo-api.d.ts.map +1 -0
  141. package/dist/komodo-api.js +104 -0
  142. package/dist/komodo-api.js.map +1 -0
  143. package/dist/komodo-notify.d.ts +4 -0
  144. package/dist/komodo-notify.d.ts.map +1 -0
  145. package/dist/komodo-notify.js +88 -0
  146. package/dist/komodo-notify.js.map +1 -0
  147. package/dist/komodo-periphery.d.ts +4 -0
  148. package/dist/komodo-periphery.d.ts.map +1 -0
  149. package/dist/komodo-periphery.js +92 -0
  150. package/dist/komodo-periphery.js.map +1 -0
  151. package/dist/komodo-server.d.ts +4 -0
  152. package/dist/komodo-server.d.ts.map +1 -0
  153. package/dist/komodo-server.js +54 -0
  154. package/dist/komodo-server.js.map +1 -0
  155. package/dist/komodo-user.d.ts +4 -0
  156. package/dist/komodo-user.d.ts.map +1 -0
  157. package/dist/komodo-user.js +66 -0
  158. package/dist/komodo-user.js.map +1 -0
  159. package/dist/komodo.d.ts +4 -0
  160. package/dist/komodo.d.ts.map +1 -0
  161. package/dist/komodo.js +222 -0
  162. package/dist/komodo.js.map +1 -0
  163. package/dist/postgres-database.d.ts +4 -0
  164. package/dist/postgres-database.d.ts.map +1 -0
  165. package/dist/postgres-database.js +88 -0
  166. package/dist/postgres-database.js.map +1 -0
  167. package/dist/postgres.d.ts +4 -0
  168. package/dist/postgres.d.ts.map +1 -0
  169. package/dist/postgres.js +95 -0
  170. package/dist/postgres.js.map +1 -0
  171. package/dist/providers.d.ts +21 -0
  172. package/dist/providers.d.ts.map +1 -0
  173. package/dist/providers.js +86 -0
  174. package/dist/providers.js.map +1 -0
  175. package/dist/repo.d.ts +4 -0
  176. package/dist/repo.d.ts.map +1 -0
  177. package/dist/repo.js +80 -0
  178. package/dist/repo.js.map +1 -0
  179. package/dist/signoz.d.ts +4 -0
  180. package/dist/signoz.d.ts.map +1 -0
  181. package/dist/signoz.js +386 -0
  182. package/dist/signoz.js.map +1 -0
  183. package/dist/ssh-probe.d.ts +5 -0
  184. package/dist/ssh-probe.d.ts.map +1 -0
  185. package/dist/ssh-probe.js +22 -0
  186. package/dist/ssh-probe.js.map +1 -0
  187. package/dist/ssh.d.ts +27 -0
  188. package/dist/ssh.d.ts.map +1 -0
  189. package/dist/ssh.js +79 -0
  190. package/dist/ssh.js.map +1 -0
  191. package/dist/tunnel.d.ts +5 -0
  192. package/dist/tunnel.d.ts.map +1 -0
  193. package/dist/tunnel.js +126 -0
  194. package/dist/tunnel.js.map +1 -0
  195. package/dist/valkey-namespace.d.ts +4 -0
  196. package/dist/valkey-namespace.d.ts.map +1 -0
  197. package/dist/valkey-namespace.js +78 -0
  198. package/dist/valkey-namespace.js.map +1 -0
  199. package/dist/valkey.d.ts +4 -0
  200. package/dist/valkey.d.ts.map +1 -0
  201. package/dist/valkey.js +94 -0
  202. package/dist/valkey.js.map +1 -0
  203. package/dist/workspace.d.ts +4 -0
  204. package/dist/workspace.d.ts.map +1 -0
  205. package/dist/workspace.js +97 -0
  206. package/dist/workspace.js.map +1 -0
  207. package/package.json +53 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Artur Kurowski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @intentic/providers
2
+
3
+ The real **Provider SPI implementations** the engine reconciles against — the only seam between a compiled graph and live infrastructure. Each provider does `read` (stateless introspection), `diff` (pure decision), and `apply` (create/update) over SSH/Docker and the Forgejo/Komodo/Cloudflare/Authentik HTTP APIs. Depends on [`@intentic/engine`](../engine) (SPI types) + [`@intentic/graph`](../graph).
4
+
5
+ ## Responsibilities
6
+
7
+ - Implement one provider per `ResourceType` and assemble them into the `ResourceType → Provider` map (`createProviders`).
8
+ - Wrap external systems behind injectable API adapters (Forgejo, Komodo, Cloudflare, Authentik, Discord, Garage) so providers stay testable.
9
+ - Own the host/SSH transport, Docker operations, DNS/tunnel routes, repos/CI, deployments, backups/restore, and identity (users/orgs/teams).
10
+ - Validate node inputs with zod (`parseInputs`) before any I/O.
11
+
12
+ ## Key files
13
+
14
+ - [src/index.ts](src/index.ts) — `createProviders` + `ProviderDeps`; re-points to every `create*Provider` factory.
15
+ - `src/<kind>.ts` — one provider per kind: e.g. [src/cloudflare.ts](src/cloudflare.ts), [src/forgejo.ts](src/forgejo.ts), [src/komodo.ts](src/komodo.ts), [src/deployment.ts](src/deployment.ts), [src/cf-route.ts](src/cf-route.ts), [src/ci.ts](src/ci.ts).
16
+ - `src/<system>-api.ts` — HTTP adapters: [src/forgejo-api.ts](src/forgejo-api.ts), [src/komodo-api.ts](src/komodo-api.ts), [src/cloudflare-api.ts](src/cloudflare-api.ts), [src/authentik-api.ts](src/authentik-api.ts); fakes like [src/forgejo-api.fake.ts](src/forgejo-api.fake.ts).
17
+ - [src/backing-ssh.ts](src/backing-ssh.ts) — `sshExecutor` (+ `SshExecutor`/`SshSession`); [src/api-validation.test.ts](src/api-validation.test.ts) — input-validation coverage.
18
+
19
+ ## How it fits
20
+
21
+ The infra boundary. `engine` defines the SPI and consumes a `Providers` map; this package is the production implementation of that map (the `cli` builds it via `createProviders`). Tests inject the fakes instead.
22
+
23
+ ## Conventions & gotchas
24
+
25
+ - Providers are constructed from injected deps/adapters — never reach for ambient globals; pass a fake adapter in tests.
26
+ - Keep `diff` pure: do all reads in `read`, all mutations in `apply`. Stamp created resources (`intentic.id=<id>`) for future orphan detection. See [ARCHITECTURE.md](../../ARCHITECTURE.md).
package/dist/app.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import type { Provider } from "@intentic/engine";
2
+ import type { KomodoApi } from "./komodo-api.js";
3
+ export declare const createAppProvider: (api?: KomodoApi) => Provider;
4
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,kBAAkB,CAAC;AAGjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAmDjD,eAAO,MAAM,iBAAiB,GAAI,MAAK,SAAqB,KAAG,QAgC7D,CAAC"}
package/dist/app.js ADDED
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ import { gitProvider, parseInputs } from "./inputs.js";
3
+ import { komodoApi } from "./komodo-api.js";
4
+ const appSchema = z.object({
5
+ komodoUrl: z.string(),
6
+ adminUser: z.string(),
7
+ adminPassword: z.string(),
8
+ repoName: z.string(),
9
+ gitInternalUrl: z.string(),
10
+ });
11
+ const parse = (inputs) => parseInputs(appSchema, inputs, "app");
12
+ const SERVER = "Local";
13
+ const BUILDER = "Local";
14
+ const buildConfig = (parsed, builderId) => {
15
+ const git = gitProvider(parsed.gitInternalUrl);
16
+ return {
17
+ builder_id: builderId,
18
+ repo: `${parsed.adminUser}/${parsed.repoName}`,
19
+ git_provider: git.domain,
20
+ git_account: parsed.adminUser,
21
+ git_https: git.https,
22
+ };
23
+ };
24
+ const ensureBuilder = async (api, baseUrl, jwt) => {
25
+ const find = async () => (await api.listBuilders({ baseUrl, jwt })).find((item) => item.name === BUILDER)?.id;
26
+ const existing = await find();
27
+ if (existing !== undefined) {
28
+ return existing;
29
+ }
30
+ await api.createBuilder({ baseUrl, jwt, name: BUILDER, config: { type: "Server", params: { server_id: SERVER } } });
31
+ const created = await find();
32
+ if (created === undefined) {
33
+ throw new Error("komodo Server builder was not created");
34
+ }
35
+ return created;
36
+ };
37
+ export const createAppProvider = (api = komodoApi) => ({
38
+ read: async (inputs, ctx) => {
39
+ if (typeof inputs["komodoUrl"] !== "string") {
40
+ return undefined;
41
+ }
42
+ const parsed = parse(inputs);
43
+ try {
44
+ const jwt = await api.login({ baseUrl: parsed.komodoUrl, username: parsed.adminUser, password: parsed.adminPassword });
45
+ const build = (await api.listBuilds({ baseUrl: parsed.komodoUrl, jwt })).find((item) => item.name === ctx.id);
46
+ if (build === undefined) {
47
+ return undefined;
48
+ }
49
+ return { outputs: {} };
50
+ }
51
+ catch (error) {
52
+ ctx.log(`app "${ctx.id}": komodo not reachable yet, treating as not-yet-created: ${String(error)}`);
53
+ return undefined;
54
+ }
55
+ },
56
+ diff: () => ({ action: "noop" }),
57
+ apply: async (inputs, _observed, ctx) => {
58
+ const parsed = parse(inputs);
59
+ const jwt = await api.login({ baseUrl: parsed.komodoUrl, username: parsed.adminUser, password: parsed.adminPassword });
60
+ const builderId = await ensureBuilder(api, parsed.komodoUrl, jwt);
61
+ const config = buildConfig(parsed, builderId);
62
+ const existing = (await api.listBuilds({ baseUrl: parsed.komodoUrl, jwt })).find((item) => item.name === ctx.id);
63
+ if (existing === undefined) {
64
+ await api.createBuild({ baseUrl: parsed.komodoUrl, jwt, name: ctx.id, config });
65
+ }
66
+ else {
67
+ await api.updateBuild({ baseUrl: parsed.komodoUrl, jwt, id: existing.id, config });
68
+ }
69
+ return {};
70
+ },
71
+ });
72
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface AuthentikClientSpec {
2
+ readonly baseUrl: string;
3
+ readonly token: string;
4
+ readonly slug: string;
5
+ readonly clientId: string;
6
+ readonly clientSecret: string;
7
+ readonly redirectDomains: readonly string[];
8
+ }
9
+ export interface AuthentikApi {
10
+ readonly findApplication: (args: {
11
+ readonly baseUrl: string;
12
+ readonly token: string;
13
+ readonly slug: string;
14
+ }) => Promise<boolean>;
15
+ readonly ensureClient: (spec: AuthentikClientSpec) => Promise<void>;
16
+ readonly deleteClient: (args: {
17
+ readonly baseUrl: string;
18
+ readonly token: string;
19
+ readonly slug: string;
20
+ }) => Promise<void>;
21
+ }
22
+ export declare const authentikApi: AuthentikApi;
23
+ //# sourceMappingURL=authentik-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authentik-api.d.ts","sourceRoot":"","sources":["../src/authentik-api.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,YAAY;IAEzB,QAAQ,CAAC,eAAe,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAElI,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpE,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/H;AAuCD,eAAO,MAAM,YAAY,EAAE,YAuC1B,CAAC"}
@@ -0,0 +1,67 @@
1
+ import { z } from "zod";
2
+ import { parseResponse } from "./inputs.js";
3
+ const listSchema = z.object({ results: z.array(z.object({ pk: z.union([z.number(), z.string()]) })) });
4
+ const scopeListSchema = z.object({ results: z.array(z.object({ pk: z.string(), scope_name: z.string() })) });
5
+ const call = async (method, baseUrl, token, path, body) => {
6
+ const response = await fetch(`${baseUrl}/api/v3${path}`, {
7
+ method,
8
+ headers: { Authorization: `Bearer ${token}`, ...(body !== undefined ? { "Content-Type": "application/json" } : {}) },
9
+ ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
10
+ });
11
+ if (!response.ok) {
12
+ throw new Error(`authentik ${method} ${path} failed (${response.status}): ${(await response.text()).slice(0, 500)}`);
13
+ }
14
+ return response;
15
+ };
16
+ const get = async (baseUrl, token, path) => (await call("GET", baseUrl, token, path)).json();
17
+ const flowPk = async (baseUrl, token, slug) => {
18
+ const result = parseResponse(z.object({ pk: z.union([z.number(), z.string()]) }), await get(baseUrl, token, `/flows/instances/${slug}/`), "authentik flow");
19
+ return result.pk;
20
+ };
21
+ const scopePks = async (baseUrl, token) => {
22
+ const result = parseResponse(scopeListSchema, await get(baseUrl, token, "/propertymappings/provider/scope/?page_size=100"), "authentik scopes");
23
+ return result.results.filter((mapping) => ["openid", "email", "profile"].includes(mapping.scope_name)).map((mapping) => mapping.pk);
24
+ };
25
+ const firstPk = (value) => parseResponse(listSchema, value, "authentik list").results[0]?.pk;
26
+ const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
27
+ export const authentikApi = {
28
+ findApplication: async ({ baseUrl, token, slug }) => firstPk(await get(baseUrl, token, `/core/applications/?slug=${slug}`)) !== undefined,
29
+ ensureClient: async ({ baseUrl, token, slug, clientId, clientSecret, redirectDomains }) => {
30
+ const [authorizationFlow, invalidationFlow, propertyMappings] = await Promise.all([
31
+ flowPk(baseUrl, token, "default-provider-authorization-implicit-consent"),
32
+ flowPk(baseUrl, token, "default-provider-invalidation-flow"),
33
+ scopePks(baseUrl, token),
34
+ ]);
35
+ const providerBody = {
36
+ name: slug,
37
+ authorization_flow: authorizationFlow,
38
+ invalidation_flow: invalidationFlow,
39
+ client_type: "confidential",
40
+ client_id: clientId,
41
+ client_secret: clientSecret,
42
+ redirect_uris: redirectDomains.map((domain) => ({ matching_mode: "regex", url: `^https://${escapeRegex(domain)}/.*$` })),
43
+ property_mappings: propertyMappings,
44
+ sub_mode: "hashed_user_id",
45
+ };
46
+ const providerPk = firstPk(await get(baseUrl, token, `/providers/oauth2/?name=${slug}`));
47
+ const provider = providerPk !== undefined
48
+ ? await call("PUT", baseUrl, token, `/providers/oauth2/${providerPk}/`, providerBody)
49
+ : await call("POST", baseUrl, token, "/providers/oauth2/", providerBody);
50
+ const pk = parseResponse(z.object({ pk: z.union([z.number(), z.string()]) }), await provider.json(), "authentik provider").pk;
51
+ const appBody = { name: slug, slug, provider: pk };
52
+ if (await authentikApi.findApplication({ baseUrl, token, slug })) {
53
+ await call("PATCH", baseUrl, token, `/core/applications/${slug}/`, { provider: pk });
54
+ }
55
+ else {
56
+ await call("POST", baseUrl, token, "/core/applications/", appBody);
57
+ }
58
+ },
59
+ deleteClient: async ({ baseUrl, token, slug }) => {
60
+ await call("DELETE", baseUrl, token, `/core/applications/${slug}/`).catch(() => undefined);
61
+ const providerPk = firstPk(await get(baseUrl, token, `/providers/oauth2/?name=${slug}`));
62
+ if (providerPk !== undefined) {
63
+ await call("DELETE", baseUrl, token, `/providers/oauth2/${providerPk}/`).catch(() => undefined);
64
+ }
65
+ },
66
+ };
67
+ //# sourceMappingURL=authentik-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authentik-api.js","sourceRoot":"","sources":["../src/authentik-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Provider } from "@intentic/engine";
2
+ import type { AuthentikApi } from "./authentik-api.js";
3
+ export declare const createAuthentikClientProvider: (api?: AuthentikApi) => Provider;
4
+ //# sourceMappingURL=authentik-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authentik-client.d.ts","sourceRoot":"","sources":["../src/authentik-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,kBAAkB,CAAC;AAEjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAkCvD,eAAO,MAAM,6BAA6B,GAAI,MAAK,YAA2B,KAAG,QA6B/E,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { z } from "zod";
2
+ import { authentikApi } from "./authentik-api.js";
3
+ import { parseInputs } from "./inputs.js";
4
+ const clientSchema = z.object({
5
+ authentikUrl: z.string(),
6
+ bootstrapToken: z.string(),
7
+ domain: z.string(),
8
+ slug: z.string(),
9
+ clientId: z.string(),
10
+ clientSecret: z.string(),
11
+ redirectDomains: z.array(z.string()).default([]),
12
+ });
13
+ const parse = (inputs) => parseInputs(clientSchema, inputs, "authentik-client");
14
+ const issuer = (parsed) => `https://${parsed.domain}/application/o/${parsed.slug}/`;
15
+ const outputsFor = (parsed) => ({
16
+ issuer: issuer(parsed),
17
+ clientId: parsed.clientId,
18
+ clientSecret: parsed.clientSecret,
19
+ });
20
+ export const createAuthentikClientProvider = (api = authentikApi) => ({
21
+ read: async (inputs, ctx) => {
22
+ const parsed = parse(inputs);
23
+ try {
24
+ const exists = await api.findApplication({ baseUrl: parsed.authentikUrl, token: parsed.bootstrapToken, slug: parsed.slug });
25
+ return exists ? { outputs: outputsFor(parsed) } : undefined;
26
+ }
27
+ catch (error) {
28
+ ctx.log(`authentik-client "${ctx.id}": authentik not reachable yet, treating as not-yet-created: ${String(error)}`);
29
+ return undefined;
30
+ }
31
+ },
32
+ diff: () => ({ action: "noop" }),
33
+ apply: async (inputs) => {
34
+ const parsed = parse(inputs);
35
+ await api.ensureClient({
36
+ baseUrl: parsed.authentikUrl,
37
+ token: parsed.bootstrapToken,
38
+ slug: parsed.slug,
39
+ clientId: parsed.clientId,
40
+ clientSecret: parsed.clientSecret,
41
+ redirectDomains: parsed.redirectDomains,
42
+ });
43
+ return outputsFor(parsed);
44
+ },
45
+ delete: async (inputs) => {
46
+ const parsed = parse(inputs);
47
+ await api.deleteClient({ baseUrl: parsed.authentikUrl, token: parsed.bootstrapToken, slug: parsed.slug });
48
+ },
49
+ });
50
+ //# sourceMappingURL=authentik-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authentik-client.js","sourceRoot":"","sources":["../src/authentik-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Provider } from "@intentic/engine";
2
+ import { type SshExecutor } from "./ssh.js";
3
+ export declare const createAuthentikProvider: (executor?: SshExecutor) => Provider;
4
+ //# sourceMappingURL=authentik.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authentik.d.ts","sourceRoot":"","sources":["../src/authentik.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,kBAAkB,CAAC;AAKjE,OAAO,EAAE,KAAK,WAAW,EAAe,MAAM,UAAU,CAAC;AAmGzD,eAAO,MAAM,uBAAuB,GAAI,WAAU,WAAyB,KAAG,QAgD5E,CAAC"}
@@ -0,0 +1,132 @@
1
+ import { z } from "zod";
2
+ import { composeDown, composeUp, containerImage, stateDir, waitReady } from "./backing-ssh.js";
3
+ import { parseInputs, sshSchema, sshTarget } from "./inputs.js";
4
+ import { sshExecutor } from "./ssh.js";
5
+ const KIND = "authentik";
6
+ const READY_TIMEOUT_MS = 300_000;
7
+ const authentikSchema = sshSchema.extend({
8
+ internalIp: z.string(),
9
+ publishPort: z.number(),
10
+ domain: z.string(),
11
+ secretKey: z.string(),
12
+ bootstrapToken: z.string(),
13
+ bootstrapPassword: z.string(),
14
+ dbPassword: z.string(),
15
+ image: z.string(),
16
+ pgImage: z.string(),
17
+ redisImage: z.string(),
18
+ });
19
+ const parse = (inputs) => parseInputs(authentikSchema, inputs, KIND);
20
+ const internalUrl = (parsed) => `http://${parsed.internalIp}:${parsed.publishPort}`;
21
+ const outputsFor = (parsed) => ({
22
+ url: `https://${parsed.domain}`,
23
+ issuerUrl: `https://${parsed.domain}/application/o/`,
24
+ internalUrl: internalUrl(parsed),
25
+ });
26
+ const composeYaml = (id, parsed) => [
27
+ "services:",
28
+ " postgresql:",
29
+ ` image: ${parsed.pgImage}`,
30
+ " restart: unless-stopped",
31
+ " environment: { POSTGRES_USER: authentik, POSTGRES_DB: authentik, POSTGRES_PASSWORD: $AUTHENTIK_POSTGRESQL__PASSWORD }",
32
+ " volumes: [ database:/var/lib/postgresql/data ]",
33
+ " healthcheck: { test: [ CMD-SHELL, pg_isready -U authentik ], interval: 10s, timeout: 5s, retries: 10 }",
34
+ " redis:",
35
+ ` image: ${parsed.redisImage}`,
36
+ " restart: unless-stopped",
37
+ ' command: [ "--save", "60", "1", "--loglevel", "warning" ]',
38
+ " volumes: [ redis:/data ]",
39
+ ' healthcheck: { test: [ CMD-SHELL, "valkey-cli ping | grep -q PONG" ], interval: 10s, timeout: 5s, retries: 10 }',
40
+ " server:",
41
+ ` image: ${parsed.image}`,
42
+ " restart: unless-stopped",
43
+ " command: server",
44
+ " env_file: ./.env",
45
+ ` ports: [ "${parsed.publishPort}:9000" ]`,
46
+ " volumes: [ media:/media, templates:/templates ]",
47
+ " depends_on: { postgresql: { condition: service_healthy }, redis: { condition: service_healthy } }",
48
+ ` labels: [ "intentic.id=${id}" ]`,
49
+ " worker:",
50
+ ` image: ${parsed.image}`,
51
+ " restart: unless-stopped",
52
+ " command: worker",
53
+ " env_file: ./.env",
54
+ " volumes: [ media:/media, certs:/certs, templates:/templates, /var/run/docker.sock:/var/run/docker.sock ]",
55
+ " depends_on: { postgresql: { condition: service_healthy }, redis: { condition: service_healthy } }",
56
+ "volumes: { database: {}, redis: {}, media: {}, certs: {}, templates: {} }",
57
+ "",
58
+ ].join("\n");
59
+ const ensureFiles = async (session, id, parsed) => {
60
+ const dir = stateDir(KIND, id);
61
+ await session.exec(`mkdir -p ${dir}`);
62
+ await session.exec(`cat > ${dir}/compose.yaml <<'COMPOSE_EOF'\n${composeYaml(id, parsed)}COMPOSE_EOF`);
63
+ const envLines = [
64
+ "AUTHENTIK_POSTGRESQL__HOST=postgresql",
65
+ "AUTHENTIK_POSTGRESQL__USER=authentik",
66
+ "AUTHENTIK_POSTGRESQL__NAME=authentik",
67
+ "AUTHENTIK_REDIS__HOST=redis",
68
+ `AUTHENTIK_BOOTSTRAP_EMAIL=akadmin@${parsed.domain}`,
69
+ `AUTHENTIK_SECRET_KEY=${parsed.secretKey}`,
70
+ `AUTHENTIK_POSTGRESQL__PASSWORD=${parsed.dbPassword}`,
71
+ `AUTHENTIK_BOOTSTRAP_PASSWORD=${parsed.bootstrapPassword}`,
72
+ `AUTHENTIK_BOOTSTRAP_TOKEN=${parsed.bootstrapToken}`,
73
+ ]
74
+ .map((line) => `'${line}'`)
75
+ .join(" ");
76
+ await session.exec(`test -f ${dir}/.env || { printf '%s\\n' ${envLines} > ${dir}/.env && chmod 600 ${dir}/.env; }`);
77
+ };
78
+ const readyProbe = (parsed) => `wget -q -O /dev/null ${internalUrl(parsed)}/-/health/ready/`;
79
+ export const createAuthentikProvider = (executor = sshExecutor) => ({
80
+ read: async (inputs, ctx) => {
81
+ const parsed = parse(inputs);
82
+ let session;
83
+ try {
84
+ session = await executor.connect(sshTarget(parsed));
85
+ }
86
+ catch (error) {
87
+ ctx.log(`authentik "${ctx.id}": host not reachable over SSH, treating as not-yet-created: ${String(error)}`);
88
+ return undefined;
89
+ }
90
+ try {
91
+ const probe = await session.exec(readyProbe(parsed));
92
+ if (probe.code !== 0) {
93
+ return undefined;
94
+ }
95
+ return { outputs: outputsFor(parsed), detail: { image: await containerImage(session, ctx.id) } };
96
+ }
97
+ finally {
98
+ await session.dispose();
99
+ }
100
+ },
101
+ diff: (inputs, observed) => {
102
+ const parsed = parse(inputs);
103
+ const image = (observed.detail?.["image"] ?? "");
104
+ return image === parsed.image
105
+ ? { action: "noop" }
106
+ : { action: "update", reason: `authentik image differs (running ${image}, want ${parsed.image})` };
107
+ },
108
+ apply: async (inputs, _observed, ctx) => {
109
+ const parsed = parse(inputs);
110
+ const session = await executor.connect(sshTarget(parsed));
111
+ try {
112
+ await ensureFiles(session, ctx.id, parsed);
113
+ await composeUp(session, KIND, ctx.id);
114
+ await waitReady(session, KIND, ctx.id, readyProbe(parsed), READY_TIMEOUT_MS);
115
+ return outputsFor(parsed);
116
+ }
117
+ finally {
118
+ await session.dispose();
119
+ }
120
+ },
121
+ delete: async (inputs, ctx) => {
122
+ const parsed = parse(inputs);
123
+ const session = await executor.connect(sshTarget(parsed));
124
+ try {
125
+ await composeDown(session, KIND, ctx.id);
126
+ }
127
+ finally {
128
+ await session.dispose();
129
+ }
130
+ },
131
+ });
132
+ //# sourceMappingURL=authentik.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authentik.js","sourceRoot":"","sources":["../src/authentik.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { SshSession } from "./ssh.js";
2
+ export declare const stateDir: (kind: string, id: string) => string;
3
+ export declare const containerId: (session: SshSession, stamp: string) => Promise<string>;
4
+ export declare const containerImage: (session: SshSession, stamp: string) => Promise<string>;
5
+ export declare const composeUp: (session: SshSession, kind: string, id: string) => Promise<void>;
6
+ export declare const composeDown: (session: SshSession, kind: string, id: string) => Promise<void>;
7
+ export declare const waitReady: (session: SshSession, kind: string, id: string, probe: string, timeoutMs: number) => Promise<void>;
8
+ //# sourceMappingURL=backing-ssh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backing-ssh.d.ts","sourceRoot":"","sources":["../src/backing-ssh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAe3C,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,EAAE,IAAI,MAAM,KAAG,MAA6C,CAAC;AAKlG,eAAO,MAAM,WAAW,GAAU,SAAS,UAAU,EAAE,OAAO,MAAM,KAAG,OAAO,CAAC,MAAM,CAGpF,CAAC;AAIF,eAAO,MAAM,cAAc,GAAU,SAAS,UAAU,EAAE,OAAO,MAAM,KAAG,OAAO,CAAC,MAAM,CAOvF,CAAC;AAGF,eAAO,MAAM,SAAS,GAAU,SAAS,UAAU,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,KAAG,OAAO,CAAC,IAAI,CAQ3F,CAAC;AAGF,eAAO,MAAM,WAAW,GAAU,SAAS,UAAU,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,KAAG,OAAO,CAAC,IAAI,CAM7F,CAAC;AAGF,eAAO,MAAM,SAAS,GAAU,SAAS,UAAU,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,EAAE,OAAO,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,IAAI,CAY7H,CAAC"}
@@ -0,0 +1,44 @@
1
+ const slug = (id) => id
2
+ .toLowerCase()
3
+ .replace(/[^a-z0-9]+/g, "-")
4
+ .replace(/^-+|-+$/g, "");
5
+ export const stateDir = (kind, id) => `/opt/intentic/${kind}/${slug(id)}`;
6
+ const projectName = (kind, id) => `intentic-${kind}-${slug(id)}`;
7
+ export const containerId = async (session, stamp) => {
8
+ const result = await session.exec(`docker ps -q --filter "label=intentic.id=${stamp}" --format '{{.ID}}'`);
9
+ return result.stdout.trim().split("\n")[0] ?? "";
10
+ };
11
+ export const containerImage = async (session, stamp) => {
12
+ const id = await containerId(session, stamp);
13
+ if (id === "") {
14
+ return "";
15
+ }
16
+ const result = await session.exec(`docker inspect --format '{{.Config.Image}}' ${id}`);
17
+ return result.stdout.trim();
18
+ };
19
+ export const composeUp = async (session, kind, id) => {
20
+ const dir = stateDir(kind, id);
21
+ const up = await session.exec(`docker compose -p ${projectName(kind, id)} --project-directory ${dir} --env-file ${dir}/.env -f ${dir}/compose.yaml up -d`);
22
+ if (up.code !== 0) {
23
+ throw new Error(`failed to bring up ${kind} "${id}": exited ${up.code}: ${up.stderr.trim()}`);
24
+ }
25
+ };
26
+ export const composeDown = async (session, kind, id) => {
27
+ const dir = stateDir(kind, id);
28
+ await session.exec(`docker compose -p ${projectName(kind, id)} --project-directory ${dir} --env-file ${dir}/.env -f ${dir}/compose.yaml down -v 2>/dev/null || true`);
29
+ await session.exec(`rm -rf ${dir}`);
30
+ };
31
+ export const waitReady = async (session, kind, id, probe, timeoutMs) => {
32
+ const deadline = Date.now() + timeoutMs;
33
+ for (;;) {
34
+ const result = await session.exec(probe);
35
+ if (result.code === 0) {
36
+ return;
37
+ }
38
+ if (Date.now() >= deadline) {
39
+ throw new Error(`${kind} "${id}" did not become ready within ${timeoutMs}ms`);
40
+ }
41
+ await new Promise((resolve) => setTimeout(resolve, 3_000));
42
+ }
43
+ };
44
+ //# sourceMappingURL=backing-ssh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backing-ssh.js","sourceRoot":"","sources":["../src/backing-ssh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { SshExecutor, SshTarget } from "./ssh.js";
2
+ export type RestoreScope = "forgejo" | "komodo" | "all";
3
+ export interface RestoreArgs {
4
+ readonly target: SshTarget;
5
+ readonly image: string;
6
+ readonly repo: string;
7
+ readonly password: string;
8
+ readonly credentials?: Record<string, string>;
9
+ readonly snapshot: string;
10
+ readonly scope: RestoreScope;
11
+ readonly log: (message: string) => void;
12
+ readonly executor?: SshExecutor;
13
+ }
14
+ export declare const restoreBackup: (args: RestoreArgs) => Promise<void>;
15
+ //# sourceMappingURL=backup-restore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup-restore.d.ts","sourceRoot":"","sources":["../src/backup-restore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAc,SAAS,EAAE,MAAM,UAAU,CAAC;AAMnE,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC;AAExD,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC;CACnC;AA2BD,eAAO,MAAM,aAAa,GAAU,MAAM,WAAW,KAAG,OAAO,CAAC,IAAI,CA2CnE,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { sshExecutor } from "./ssh.js";
2
+ const RESTORE_VOLUME = "intentic-restore";
3
+ const resticPrefix = (args) => {
4
+ const creds = Object.entries(args.credentials ?? {})
5
+ .map(([key, value]) => `-e ${key}='${value}'`)
6
+ .join(" ");
7
+ return `docker run --rm -e RESTIC_PASSWORD='${args.password}' ${creds} -v ${RESTORE_VOLUME}:/restore ${args.image} -r '${args.repo}'`;
8
+ };
9
+ const restoreVolume = (args, volume, sub) => `docker run --rm --entrypoint sh -v ${volume}:/dest -v ${RESTORE_VOLUME}:/restore ${args.image} ` +
10
+ `-c 'rm -rf /dest/..?* /dest/.[!.]* /dest/* 2>/dev/null; cp -a /restore/volumes/${sub}/. /dest/'`;
11
+ const wants = (scope, part) => scope === "all" || scope === part;
12
+ export const restoreBackup = async (args) => {
13
+ const executor = args.executor ?? sshExecutor;
14
+ const session = await executor.connect(args.target);
15
+ const run = async (command, what) => {
16
+ const result = await session.exec(command);
17
+ if (result.code !== 0) {
18
+ throw new Error(`restore: ${what} failed (exit ${result.code}): ${result.stderr.trim()}`);
19
+ }
20
+ };
21
+ try {
22
+ args.log(`restoring snapshot "${args.snapshot}" (${args.scope}) from ${args.repo}`);
23
+ await run(`docker volume create ${RESTORE_VOLUME}`, "create restore volume");
24
+ await run(`${resticPrefix(args)} restore '${args.snapshot}' --target /restore`, "restic restore");
25
+ if (wants(args.scope, "forgejo")) {
26
+ await session.exec("docker rm -f intentic-forgejo intentic-forgejo-runner 2>/dev/null || true");
27
+ await run(restoreVolume(args, "intentic-forgejo-data", "forgejo"), "restore forgejo volume");
28
+ args.log("restored Forgejo data volume");
29
+ }
30
+ if (wants(args.scope, "komodo")) {
31
+ await session.exec('ids=$(docker ps -aq -f label=com.docker.compose.project=komodo); [ -n "$ids" ] && docker rm -f $ids || true');
32
+ await run(restoreVolume(args, "komodo_postgres-data", "komodo-postgres"), "restore komodo postgres volume");
33
+ await run(restoreVolume(args, "komodo_keys", "komodo-keys"), "restore komodo keys volume");
34
+ await run(restoreVolume(args, "komodo_ferretdb-state", "komodo-ferretdb"), "restore komodo ferretdb volume");
35
+ args.log("restored Komodo data volumes");
36
+ }
37
+ if (args.scope === "all") {
38
+ await run(`docker run --rm --entrypoint sh -v /opt/intentic:/dest -v ${RESTORE_VOLUME}:/restore ${args.image} ` +
39
+ "-c 'cp -a /restore/host-opt-intentic/. /dest/'", "restore /opt/intentic state");
40
+ args.log("restored /opt/intentic host state");
41
+ }
42
+ await session.exec(`docker volume rm ${RESTORE_VOLUME} 2>/dev/null || true`);
43
+ args.log('restore complete — run "intentic apply" to bring the services back up on the restored data');
44
+ }
45
+ finally {
46
+ await session.dispose();
47
+ }
48
+ };
49
+ //# sourceMappingURL=backup-restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup-restore.js","sourceRoot":"","sources":["../src/backup-restore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Provider } from "@intentic/engine";
2
+ import type { SshExecutor } from "./ssh.js";
3
+ export declare const createBackupProvider: (executor?: SshExecutor) => Provider;
4
+ //# sourceMappingURL=backup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,kBAAkB,CAAC;AAGjE,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,UAAU,CAAC;AAkHxD,eAAO,MAAM,oBAAoB,GAAI,WAAU,WAAyB,KAAG,QAwEzE,CAAC"}