openship 0.6.5 → 0.6.7

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/bare-7QD623QV.js +29 -0
  2. package/dist/chunk-2ANV5ZQ5.js +88 -0
  3. package/dist/{chunk-LEYSL46B.js → chunk-2VSW6Q6C.js} +3911 -898
  4. package/dist/{chunk-5OUWIPOB.js → chunk-5T4UVOM3.js} +16 -86
  5. package/dist/{chunk-EZPPTWJQ.js → chunk-BLEXTYRK.js} +1 -1
  6. package/dist/{chunk-3ZAGC5NT.js → chunk-CIJV43LH.js} +83 -33
  7. package/dist/{chunk-7S4USQYF.js → chunk-DDFUESPJ.js} +67 -124
  8. package/dist/{chunk-6FH4AXVY.js → chunk-E2X26PXR.js} +1 -1
  9. package/dist/{chunk-XVOBL7BC.js → chunk-FYPFEDPZ.js} +1 -1
  10. package/dist/{chunk-WFRXYWK2.js → chunk-FZ6QCF6B.js} +8 -6
  11. package/dist/{chunk-VHMOQL5Y.js → chunk-GGIAIGUL.js} +125 -80
  12. package/dist/{chunk-WE7BXW6L.js → chunk-GIPJNNI5.js} +38 -44
  13. package/dist/{chunk-ZFJXPCQP.js → chunk-H3WT3A6R.js} +4 -3
  14. package/dist/chunk-H4FS5BED.js +936 -0
  15. package/dist/{chunk-HPXP6LXZ.js → chunk-J2XM3QSP.js} +8 -5
  16. package/dist/{chunk-6JELW75A.js → chunk-J3K6XABC.js} +5 -5
  17. package/dist/{chunk-VDESJSG6.js → chunk-LHFXSC36.js} +558 -109
  18. package/dist/{chunk-MSZUCNPV.js → chunk-MEE6OZFP.js} +3 -3
  19. package/dist/chunk-N5YZMO33.js +111 -0
  20. package/dist/{chunk-VLQ3UIVO.js → chunk-NRTJRNAE.js} +105 -37
  21. package/dist/chunk-PPEBIY5F.js +2331 -0
  22. package/dist/{chunk-RFWJE7ZN.js → chunk-PVP4RGWT.js} +3 -3
  23. package/dist/{chunk-PZRRL5PC.js → chunk-QHMDCYZ3.js} +15 -4
  24. package/dist/chunk-R4VDPFLS.js +106 -0
  25. package/dist/chunk-RDXT4BQB.js +310 -0
  26. package/dist/{chunk-GRTXMUHA.js → chunk-S6B2Z3OO.js} +145 -60
  27. package/dist/chunk-UWEV6XTS.js +249 -0
  28. package/dist/{chunk-QLX7NBEA.js → chunk-VQM6JHJB.js} +1004 -2046
  29. package/dist/{chunk-A7EWM2KA.js → chunk-VSTFHUCV.js} +44 -50
  30. package/dist/chunk-WU54BXFE.js +70 -0
  31. package/dist/{chunk-LFCSC4IU.js → chunk-XWHWTHEL.js} +313 -469
  32. package/dist/{chunk-7334NSJL.js → chunk-ZPJ74LXE.js} +76 -38
  33. package/dist/cloud-KNNABE3O.js +40 -0
  34. package/dist/{detect-P4CIQBRH.js → detect-G4DR3U2N.js} +9 -6
  35. package/dist/{docker-3K2NEBD6.js → docker-YOVPCIB4.js} +11 -7
  36. package/dist/{docker-edge-executor-YZZ6P7IC.js → docker-edge-executor-QFXD3337.js} +8 -6
  37. package/dist/edge-import-CRFVSR6P.js +56 -0
  38. package/dist/{edge-preflight-ES6FH4JK.js → edge-preflight-MXERVAMG.js} +15 -12
  39. package/dist/{ensure-container-edge-YPITNH45.js → ensure-container-edge-F4JUNQIK.js} +13 -10
  40. package/dist/{executor-DZGX55K2.js → executor-CVPAYYHR.js} +10 -5
  41. package/dist/host-channel-preflight-QTDNGLCK.js +54 -0
  42. package/dist/index.js +139 -92
  43. package/dist/{local-executor-WOFZD72X.js → local-executor-ODC6RANU.js} +3 -2
  44. package/dist/{nginx-NSAHWGJV.js → nginx-KLFF43TC.js} +13 -8
  45. package/dist/{openresty-lua-DR4D3EZ6.js → openresty-lua-VKWUV4GB.js} +8 -5
  46. package/dist/{privilege-YTVI4SKF.js → privilege-7D3SSOL3.js} +6 -5
  47. package/dist/server/engine/samples/amavisd/amavisd.conf +25 -0
  48. package/dist/server/engine/samples/postfix/master.cf +14 -0
  49. package/dist/server/index.js +44526 -33476
  50. package/dist/server/migrations/0105_mail_inbound_rules.sql +80 -0
  51. package/dist/server/migrations/0106_mcp_call_tracking.sql +23 -0
  52. package/dist/server/migrations/0107_build_minute_metering_indexes.sql +20 -0
  53. package/dist/server/migrations/0108_credential.sql +68 -0
  54. package/dist/server/migrations/meta/_journal.json +28 -0
  55. package/dist/setup-I5AJC6NJ.js +25 -0
  56. package/dist/ssh-client-625VWGKP.js +29 -0
  57. package/dist/up-QXTOOVXC.js +61 -0
  58. package/package.json +1 -1
  59. package/dist/bare-XQIPDO4R.js +0 -24
  60. package/dist/chunk-6HOA5JT7.js +0 -124
  61. package/dist/chunk-TM2IQPYU.js +0 -434
  62. package/dist/chunk-XRNRT37W.js +0 -316
  63. package/dist/cloud-3DODOWTR.js +0 -36
  64. package/dist/edge-import-MCJNVTZ2.js +0 -51
  65. package/dist/host-channel-preflight-MUXE3KZU.js +0 -49
  66. package/dist/setup-WUUZURHS.js +0 -22
  67. package/dist/up-XEO3SR6Z.js +0 -58
  68. /package/dist/{dist-es-ZP5QDSJ3.js → dist-es-AXFRS7PS.js} +0 -0
@@ -0,0 +1,80 @@
1
+ -- Inbound-mail notification rules — "mail arrives at a watched address, tell me in a channel".
2
+ --
3
+ -- Capture is Postfix's own `recipient_bcc_maps`, which the shipped main.cf already points
4
+ -- at two SQL tables in the engine's `vmail` DB (main.cf.pgsql:36-38). Arming a rule is
5
+ -- therefore ONE row in `vmail.recipient_bcc_domain` — no postmap, no reload, no container
6
+ -- recreate, and identical on the container and legacy host flavors, so it reaches every
7
+ -- mail box already provisioned.
8
+ --
9
+ -- ONE TABLE, ON PURPOSE. The obvious second table — a record of each armed collector —
10
+ -- would only cache state the mail engine already holds authoritatively: the token is
11
+ -- literally inside `recipient_bcc_domain.bcc_address`
12
+ -- (`openship-hook+<token>@<domain>`), the maildir is in `vmail.mailbox`, and "a foreign
13
+ -- BCC took the slot" is derivable by comparing that address against our own prefix. A
14
+ -- cache of the engine's own state is a thing that goes stale; the collector is READ from
15
+ -- vmail instead.
16
+ --
17
+ -- What genuinely has to persist here is the RULES: they reference
18
+ -- `notification_channel` ids, which exist only in this database, and they are created and
19
+ -- edited from a dashboard tab. Keeping them on the mail box would make every list and
20
+ -- toggle an SSH round-trip, and would make the rules unreadable exactly when the mail box
21
+ -- is unreachable.
22
+ --
23
+ -- No cursor table either. The BCC copy is a full message in the collector's maildir, so
24
+ -- the read job dispatches and then DELETES the file: deletion is the cursor, and it
25
+ -- doubles as the prune that keeps a second full copy of every watched message from
26
+ -- growing forever on a bind mount with no quota of its own.
27
+ CREATE TABLE IF NOT EXISTS "mail_inbound_rule" (
28
+ "id" text PRIMARY KEY NOT NULL,
29
+ "server_id" text NOT NULL REFERENCES "mail_servers"("server_id") ON DELETE CASCADE,
30
+ -- Carried so dispatch can fan out to the right org's channels without joining back
31
+ -- through `servers`. This does NOT make the table organization-scope for dump purposes
32
+ -- (see dump.ts): its FK targets are instance-scope.
33
+ "organization_id" text NOT NULL REFERENCES "organization"("id") ON DELETE CASCADE,
34
+ -- Operator-facing label, e.g. "Support inbox → #support".
35
+ "name" text NOT NULL,
36
+ -- mailbox | domain | all. Text, not an enum: a new scope should be a registry entry and
37
+ -- a UI option, not a migration.
38
+ "scope" text NOT NULL,
39
+ -- Full address for `mailbox`, the domain for `domain`, NULL for `all`.
40
+ --
41
+ -- `all` is a genuine fan-out: there is no global `always_bcc` anywhere in the shipped
42
+ -- Postfix config, and the domain lookup keys on exact equality with no wildcard
43
+ -- convention — so it arms one row per domain and needs a reconcile when a domain is
44
+ -- added. There is deliberately no CHECK tying scope to target: this schema has no CHECK
45
+ -- constraints anywhere, and the SQL and the drizzle schema are hand-maintained in
46
+ -- parallel. The invariant is enforced fail-closed at the write boundary and in the
47
+ -- filter, where a mailbox rule with no target matches NOTHING rather than everything.
48
+ "target" text,
49
+ -- Optional extra matching, applied in the control plane at filter time so editing one
50
+ -- never touches the mail box. NULL = match everything.
51
+ "from_pattern" text,
52
+ "subject_pattern" text,
53
+ -- Spam gate, and not optional in practice. The shipped amavis policy sets
54
+ -- spam_lover='Y' AND bad_header_lover='Y' on the catch-all '@.' policy with empty
55
+ -- quarantine targets, so the global $final_spam_destiny = D_DISCARD is dead for every
56
+ -- recipient: spam and bad-header mail ARE delivered and therefore ARE captured.
57
+ -- Nothing upstream filters on our behalf.
58
+ "max_spam_score" real,
59
+ -- Channel ids as a jsonb array, deliberately NOT a join table with an FK to
60
+ -- notification_channel: the dump's FK_PARENT maps a bare `channelId` column to that
61
+ -- table unconditionally for ANY table, which would make assertDumpSelfContained reject
62
+ -- any dump carrying a real join row on a remap path.
63
+ "channel_ids" jsonb NOT NULL DEFAULT '[]'::jsonb,
64
+ "enabled" boolean NOT NULL DEFAULT true,
65
+ -- Burst control state. The notification subsystem has no rate limiting or windowed
66
+ -- dedup of its own — that is explicitly the producer's job — so a mailing list hitting
67
+ -- a watched address must not become one alert per message.
68
+ "paused_reason" text,
69
+ "last_matched_at" timestamp,
70
+ "created_at" timestamp NOT NULL DEFAULT now(),
71
+ "updated_at" timestamp NOT NULL DEFAULT now()
72
+ );
73
+ --> statement-breakpoint
74
+ -- The dispatch path's read on every tick: "enabled rules for this server".
75
+ CREATE INDEX IF NOT EXISTS "idx_mail_inbound_rule_server_enabled"
76
+ ON "mail_inbound_rule" ("server_id", "enabled");
77
+ --> statement-breakpoint
78
+ -- The rules tab lists per org.
79
+ CREATE INDEX IF NOT EXISTS "idx_mail_inbound_rule_org"
80
+ ON "mail_inbound_rule" ("organization_id");
@@ -0,0 +1,23 @@
1
+ -- MCP observability: attribute an audit row to the CLIENT that made it, and
2
+ -- count how much a credential is used.
3
+ --
4
+ -- `source` already said "an AI assistant did this" (0088), unforgeably — but not
5
+ -- WHICH assistant. With two clients connected under one user (Claude Desktop and
6
+ -- Cursor, say) every row read the same, so "what did this agent do" could not be
7
+ -- answered and disconnecting the wrong one was a coin flip. The column holds the
8
+ -- canonical principal id the auth layer already mints (`oauth:<clientId>` /
9
+ -- `pat:<tokenId>`), so it resolves to a name through existing tables.
10
+ --
11
+ -- The index is PARTIAL: only MCP rows ever carry a client id, and mcp.tool_called
12
+ -- makes audit_event's highest-volume writer, so indexing the NULLs would be paid
13
+ -- for on every insert in the table for no read.
14
+ ALTER TABLE "audit_event" ADD COLUMN IF NOT EXISTS "source_client_id" text;--> statement-breakpoint
15
+ CREATE INDEX IF NOT EXISTS "audit_event_org_client_idx"
16
+ ON "audit_event" ("organization_id", "source_client_id", "created_at" DESC)
17
+ WHERE "source_client_id" IS NOT NULL;--> statement-breakpoint
18
+
19
+ -- Call counter for every bearer credential (manual PATs and the OAuth-binding
20
+ -- rows behind MCP connections alike). NOT NULL DEFAULT 0 is safe here: existing
21
+ -- rows genuinely have no counted history, and 0 alongside a non-null
22
+ -- `last_used_at` reads correctly as "used before counting existed".
23
+ ALTER TABLE "personal_access_token" ADD COLUMN IF NOT EXISTS "use_count" integer DEFAULT 0 NOT NULL;
@@ -0,0 +1,20 @@
1
+ -- Indexes for the build-minute allowance query.
2
+ --
3
+ -- `sumBuildMillisForOrg` joins build_session → deployment, filters on
4
+ -- deployment.organization_id and windows on build_session.started_at. It used to
5
+ -- run only on the billing page (once, on demand); it now runs on the plan gate in
6
+ -- `createQueuedDeployment`, i.e. on every deploy. Neither side of that join had a
7
+ -- supporting index — build_session carried only its primary key and
8
+ -- deployment.organization_id had none — so the query was a double sequential scan
9
+ -- whose cost grows with TOTAL deployment history across all orgs, not with the
10
+ -- org being checked.
11
+ --
12
+ -- (domain.project_id, which the free-subdomain count joins on, is already covered
13
+ -- by idx_domain_project.)
14
+ CREATE INDEX IF NOT EXISTS "idx_build_session_started_at"
15
+ ON "build_session" ("started_at");--> statement-breakpoint
16
+
17
+ -- Org scoping for the same join. Also serves the org-wide deployment listings,
18
+ -- which had been scanning for the same reason.
19
+ CREATE INDEX IF NOT EXISTS "idx_deployment_org"
20
+ ON "deployment" ("organization_id");
@@ -0,0 +1,68 @@
1
+ -- Third-party credentials, in one place.
2
+ --
3
+ -- Openship needs other people's secrets for unrelated jobs — write a DNS record, pull a
4
+ -- private image, later push a backup — and each job grew its own storage: a single token
5
+ -- column on `dns_credential`, FIVE encrypted columns inlined on a backup destination, a
6
+ -- channel's own on notifications. Same `enc1:` envelope in each, three shapes, three
7
+ -- forms in the UI, and no way to reuse one credential for two features.
8
+ --
9
+ -- The unit here is the CREDENTIAL, deliberately not the thing that uses it. A backup
10
+ -- destination is a place, a DNS zone is a zone, a notification channel is a route; each
11
+ -- keeps its own row and points at a credential. That is what makes "one Cloudflare token
12
+ -- for every zone" and "one ghcr.io login for every project" possible — the reuse is the
13
+ -- point, fewer screens is the side effect.
14
+ --
15
+ -- Shape notes:
16
+ -- • `provider` is TEXT, matching dns_credential's reasoning: adding a provider should
17
+ -- be a registry entry in @repo/core, not a migration.
18
+ -- • `selector` is what the credential APPLIES TO when one per provider is not enough —
19
+ -- a registry host for `docker-registry`, NULL for an org-wide `cloudflare` token. It
20
+ -- is stored normalized (see normalizeCredentialSelector) so the value a pull derives
21
+ -- from an image reference matches the value the operator typed.
22
+ -- • `secrets_enc` is ONE `enc1:` AES-256-GCM envelope over a JSON object, so a provider
23
+ -- with several secret fields (an S3 key pair, an SFTP key + passphrase) needs no new
24
+ -- columns. The readable half lives in `public_fields`, which is what the API can
25
+ -- return without decrypting anything.
26
+ -- • `status` + `last_error` exist so a credential that was revoked upstream becomes
27
+ -- VISIBLE instead of silently failing every deploy or backup forever. `last_error` is
28
+ -- the provider's redacted reason, never its response body.
29
+ CREATE TABLE IF NOT EXISTS "credential" (
30
+ "id" text PRIMARY KEY NOT NULL,
31
+ "organization_id" text NOT NULL REFERENCES "organization"("id") ON DELETE CASCADE,
32
+ -- Provider id from CREDENTIAL_PROVIDERS ("docker-registry", "cloudflare").
33
+ "provider" text NOT NULL,
34
+ -- Operator-facing label, e.g. "GHCR read-only".
35
+ "name" text NOT NULL,
36
+ -- The resource this credential is for, normalized; NULL when the provider is org-wide.
37
+ "selector" text,
38
+ -- Non-secret fields (username, region, endpoint) — returned by the API as-is.
39
+ "public_fields" jsonb NOT NULL DEFAULT '{}'::jsonb,
40
+ -- Every secret field for this provider, as one enc1: envelope over a JSON object.
41
+ "secrets_enc" text NOT NULL,
42
+ -- active | invalid. Flipped to 'invalid' the moment a provider answers 401/403, which
43
+ -- is the only time we learn a stored credential stopped working.
44
+ "status" text NOT NULL DEFAULT 'active',
45
+ "last_verified_at" timestamp,
46
+ -- Redacted reason the last verify or use failed. Never provider response bodies.
47
+ "last_error" text,
48
+ "created_at" timestamp NOT NULL DEFAULT now(),
49
+ "updated_at" timestamp NOT NULL DEFAULT now()
50
+ );
51
+ --> statement-breakpoint
52
+ -- The resolve path asks exactly one question — "this org's credential for this provider
53
+ -- and this resource" — on every deploy that pulls and every domain that provisions.
54
+ -- Leading org column means the plain org-wide listing and the per-provider listing both
55
+ -- ride this index as prefixes, so it is the only lookup index the table needs. `status`
56
+ -- is filtered in code: a handful of rows per org makes an extra column here dead weight.
57
+ CREATE INDEX IF NOT EXISTS "idx_credential_org_provider_selector"
58
+ ON "credential" ("organization_id", "provider", "selector");
59
+ --> statement-breakpoint
60
+ -- One label per provider per resource per org. A second "GHCR read-only" for the same
61
+ -- host is a double-submit, and two credentials matching one registry makes "which one
62
+ -- authenticated this pull" unanswerable when one of them starts failing.
63
+ --
64
+ -- COALESCE, not a bare column: Postgres treats NULLs as DISTINCT in a unique index, so
65
+ -- an org-wide provider (selector IS NULL — every Cloudflare token) would accept
66
+ -- unlimited duplicates of the same name and this constraint would quietly do nothing.
67
+ CREATE UNIQUE INDEX IF NOT EXISTS "uq_credential_org_provider_selector_name"
68
+ ON "credential" ("organization_id", "provider", COALESCE("selector", ''), "name");
@@ -736,6 +736,34 @@
736
736
  "when": 1787955707325,
737
737
  "tag": "0104_instance_host_control",
738
738
  "breakpoints": true
739
+ },
740
+ {
741
+ "idx": 105,
742
+ "version": "7",
743
+ "when": 1788042107325,
744
+ "tag": "0105_mail_inbound_rules",
745
+ "breakpoints": true
746
+ },
747
+ {
748
+ "idx": 106,
749
+ "version": "7",
750
+ "when": 1788128507325,
751
+ "tag": "0106_mcp_call_tracking",
752
+ "breakpoints": true
753
+ },
754
+ {
755
+ "idx": 107,
756
+ "version": "7",
757
+ "when": 1788214907325,
758
+ "tag": "0107_build_minute_metering_indexes",
759
+ "breakpoints": true
760
+ },
761
+ {
762
+ "idx": 108,
763
+ "version": "7",
764
+ "when": 1788301307325,
765
+ "tag": "0108_credential",
766
+ "breakpoints": true
739
767
  }
740
768
  ]
741
769
  }
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env sh
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
+ import { createRequire as __ospCreateRequire } from "node:module";
4
+ const require = __ospCreateRequire(import.meta.url);
5
+ import {
6
+ SystemManager
7
+ } from "./chunk-FYPFEDPZ.js";
8
+ import "./chunk-ZPJ74LXE.js";
9
+ import "./chunk-NRTJRNAE.js";
10
+ import "./chunk-QHMDCYZ3.js";
11
+ import "./chunk-I3DPMTSF.js";
12
+ import "./chunk-R4VDPFLS.js";
13
+ import "./chunk-PVP4RGWT.js";
14
+ import "./chunk-BLEXTYRK.js";
15
+ import "./chunk-FZ6QCF6B.js";
16
+ import "./chunk-H3WT3A6R.js";
17
+ import "./chunk-GIPJNNI5.js";
18
+ import "./chunk-VSTFHUCV.js";
19
+ import "./chunk-UWEV6XTS.js";
20
+ import "./chunk-N5YZMO33.js";
21
+ import "./chunk-2VSW6Q6C.js";
22
+ import "./chunk-PXKCZB2I.js";
23
+ export {
24
+ SystemManager
25
+ };
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env sh
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
+ import { createRequire as __ospCreateRequire } from "node:module";
4
+ const require = __ospCreateRequire(import.meta.url);
5
+ import {
6
+ DOCKER_DIAL_STDIO_COMMAND,
7
+ attachDialStdioDiagnostics,
8
+ connectSshClient,
9
+ dialStdioDiagnostics,
10
+ execSshCommand,
11
+ openDockerDialStdioChannel,
12
+ openSftp,
13
+ openSshExecChannel,
14
+ openSshUnixSocket
15
+ } from "./chunk-5T4UVOM3.js";
16
+ import "./chunk-N5YZMO33.js";
17
+ import "./chunk-2VSW6Q6C.js";
18
+ import "./chunk-PXKCZB2I.js";
19
+ export {
20
+ DOCKER_DIAL_STDIO_COMMAND,
21
+ attachDialStdioDiagnostics,
22
+ connectSshClient,
23
+ dialStdioDiagnostics,
24
+ execSshCommand,
25
+ openDockerDialStdioChannel,
26
+ openSftp,
27
+ openSshExecChannel,
28
+ openSshUnixSocket
29
+ };
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env sh
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
+ import { createRequire as __ospCreateRequire } from "node:module";
4
+ const require = __ospCreateRequire(import.meta.url);
5
+ import {
6
+ normalizeUrl,
7
+ runHeadlessProvision,
8
+ startService,
9
+ upCommand
10
+ } from "./chunk-DDFUESPJ.js";
11
+ import "./chunk-PPEBIY5F.js";
12
+ import "./chunk-RDXT4BQB.js";
13
+ import "./chunk-VQM6JHJB.js";
14
+ import "./chunk-QWHBRY2K.js";
15
+ import "./chunk-J2XM3QSP.js";
16
+ import "./chunk-ELGRMZOW.js";
17
+ import "./chunk-FYPFEDPZ.js";
18
+ import "./chunk-ONKEYSMY.js";
19
+ import "./chunk-XZYFZ6A5.js";
20
+ import "./chunk-PDW4L3NV.js";
21
+ import "./chunk-DOD2BXHQ.js";
22
+ import "./chunk-42WQABXM.js";
23
+ import "./chunk-DRK3MEDS.js";
24
+ import "./chunk-3NQQXMDR.js";
25
+ import "./chunk-ZWLDLTJP.js";
26
+ import "./chunk-J3K6XABC.js";
27
+ import "./chunk-CIJV43LH.js";
28
+ import "./chunk-ZPJ74LXE.js";
29
+ import "./chunk-NRTJRNAE.js";
30
+ import "./chunk-QHMDCYZ3.js";
31
+ import "./chunk-I3DPMTSF.js";
32
+ import "./chunk-WNWQBB7F.js";
33
+ import "./chunk-2GWYYHOR.js";
34
+ import "./chunk-RXQBD4ZY.js";
35
+ import "./chunk-LHFXSC36.js";
36
+ import "./chunk-XWHWTHEL.js";
37
+ import "./chunk-S6B2Z3OO.js";
38
+ import "./chunk-MEE6OZFP.js";
39
+ import "./chunk-WU54BXFE.js";
40
+ import "./chunk-H4FS5BED.js";
41
+ import "./chunk-GGIAIGUL.js";
42
+ import "./chunk-R4VDPFLS.js";
43
+ import "./chunk-2ANV5ZQ5.js";
44
+ import "./chunk-5T4UVOM3.js";
45
+ import "./chunk-E2X26PXR.js";
46
+ import "./chunk-PVP4RGWT.js";
47
+ import "./chunk-BLEXTYRK.js";
48
+ import "./chunk-FZ6QCF6B.js";
49
+ import "./chunk-H3WT3A6R.js";
50
+ import "./chunk-GIPJNNI5.js";
51
+ import "./chunk-VSTFHUCV.js";
52
+ import "./chunk-UWEV6XTS.js";
53
+ import "./chunk-N5YZMO33.js";
54
+ import "./chunk-2VSW6Q6C.js";
55
+ import "./chunk-PXKCZB2I.js";
56
+ export {
57
+ normalizeUrl,
58
+ runHeadlessProvision,
59
+ startService,
60
+ upCommand
61
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openship",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "Openship CLI - deploy, manage, and open your Openship platform from the terminal",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env sh
2
- ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
- import { createRequire as __ospCreateRequire } from "node:module";
4
- const require = __ospCreateRequire(import.meta.url);
5
- import {
6
- BareRuntime,
7
- STATIC_RELEASE_BASE
8
- } from "./chunk-GRTXMUHA.js";
9
- import "./chunk-MSZUCNPV.js";
10
- import "./chunk-TM2IQPYU.js";
11
- import "./chunk-VHMOQL5Y.js";
12
- import "./chunk-5OUWIPOB.js";
13
- import "./chunk-6FH4AXVY.js";
14
- import "./chunk-RFWJE7ZN.js";
15
- import "./chunk-A7EWM2KA.js";
16
- import "./chunk-EZPPTWJQ.js";
17
- import "./chunk-WFRXYWK2.js";
18
- import "./chunk-ZFJXPCQP.js";
19
- import "./chunk-LEYSL46B.js";
20
- import "./chunk-PXKCZB2I.js";
21
- export {
22
- BareRuntime,
23
- STATIC_RELEASE_BASE
24
- };
@@ -1,124 +0,0 @@
1
- #!/usr/bin/env sh
2
- ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
- import { createRequire as __ospCreateRequire } from "node:module";
4
- const require = __ospCreateRequire(import.meta.url);
5
- import {
6
- composeInternalToken,
7
- startUnitHint
8
- } from "./chunk-QLX7NBEA.js";
9
- import {
10
- LocalExecutor
11
- } from "./chunk-6FH4AXVY.js";
12
- import {
13
- EDGE_CONTAINER_NAME,
14
- edgeCrashReason
15
- } from "./chunk-WE7BXW6L.js";
16
-
17
- // src/lib/edge-import.ts
18
- import chalk from "chalk";
19
- import ora from "ora";
20
- async function waitForApiHealth(port, tries) {
21
- for (let i = 0; i < tries; i++) {
22
- try {
23
- const r = await fetch(`http://127.0.0.1:${port}/api/health`, { signal: AbortSignal.timeout(2e3) });
24
- if (r.ok) return true;
25
- } catch {
26
- }
27
- await new Promise((r) => setTimeout(r, 1e3));
28
- }
29
- return false;
30
- }
31
- async function waitForEdgeRunning(tries) {
32
- const exec = new LocalExecutor();
33
- for (let i = 0; i < tries; i++) {
34
- const out = await exec.exec(`docker inspect -f '{{.State.Running}}' ${EDGE_CONTAINER_NAME}`).catch(() => "");
35
- if (out.trim() === "true") return true;
36
- await new Promise((r) => setTimeout(r, 1e3));
37
- }
38
- return false;
39
- }
40
- async function importMigratedSites(apiPort, sites, certPems, staticRootOverrides) {
41
- const token = composeInternalToken();
42
- if (!token) {
43
- const error = "couldn't read the stack's internal token";
44
- console.log(chalk.yellow(` Skipping site import \u2014 ${error}. Re-run to retry.
45
- `));
46
- return { ok: false, registered: [], error };
47
- }
48
- const spinner = ora(
49
- `Importing ${sites.length} migrated site${sites.length === 1 ? "" : "s"} into the edge\u2026`
50
- ).start();
51
- if (!await waitForApiHealth(apiPort, 60)) {
52
- const error = "API didn't become healthy in time";
53
- spinner.warn(`${error} \u2014 migrated sites not imported. Re-run \`openship up\` to retry.`);
54
- return { ok: false, registered: [], error };
55
- }
56
- if (!await waitForEdgeRunning(60)) {
57
- const error = `the ${EDGE_CONTAINER_NAME} container isn't running yet`;
58
- spinner.warn(`${error} \u2014 migrated sites not imported. Re-run \`openship up\` to retry.`);
59
- return { ok: false, registered: [], error };
60
- }
61
- try {
62
- const r = await fetch(`http://127.0.0.1:${apiPort}/api/system/edge/import-sites`, {
63
- method: "POST",
64
- headers: { "Content-Type": "application/json", "X-Internal-Token": token },
65
- body: JSON.stringify({ sites, certPems, staticRootOverrides }),
66
- signal: AbortSignal.timeout(12e4)
67
- });
68
- const data = await r.json().catch(() => ({}));
69
- if (!r.ok) {
70
- const error = data.error ?? `HTTP ${r.status}`;
71
- spinner.warn(`Site import failed: ${error}. Re-run to retry.`);
72
- return { ok: false, registered: [], error };
73
- }
74
- const registered = data.registered ?? [];
75
- const warnings = data.warnings ?? [];
76
- const missed = sites.length - registered.length;
77
- if (sites.length > 0 && registered.length === 0) {
78
- spinner.fail(
79
- `Migrated NONE of the ${sites.length} site${sites.length === 1 ? "" : "s"} \u2014 Openship holds :80/:443 and ${sites.length === 1 ? "that hostname is" : "those hostnames are"} NOT being served.`
80
- );
81
- for (const w of warnings.slice(0, 8)) console.log(chalk.red(` \u2022 ${w}`));
82
- const edgeLog = await edgeCrashReason(new LocalExecutor());
83
- if (edgeLog) {
84
- console.log(chalk.red(`
85
- The edge container is not running. Its log says:`));
86
- console.log(chalk.red(` ${edgeLog}`));
87
- }
88
- const back = startUnitHint("nginx");
89
- console.log(
90
- chalk.yellow(
91
- `
92
- Retry the import with \`openship up\` once the cause above is fixed, or put your
93
- ` + (back ? ` previous proxy back: docker stop ${EDGE_CONTAINER_NAME} && ${back}
94
- ` : ` previous proxy back by stopping ${EDGE_CONTAINER_NAME} and starting it the way
95
- this host starts services.
96
- `)
97
- )
98
- );
99
- return { ok: false, registered, error: warnings[0] ?? "no sites were registered" };
100
- }
101
- if (missed > 0) {
102
- spinner.warn(
103
- `Migrated ${registered.length}/${sites.length} sites \u2014 ${missed} not served (see below).`
104
- );
105
- for (const w of warnings.slice(0, 8)) console.log(chalk.yellow(` \u2022 ${w}`));
106
- return { ok: false, registered, error: `${missed} site(s) not registered` };
107
- }
108
- spinner.succeed(
109
- `Migrated ${registered.length} site${registered.length === 1 ? "" : "s"} into Openship's edge.`
110
- );
111
- for (const w of warnings.slice(0, 8)) console.log(chalk.dim(` \u2022 ${w}`));
112
- return { ok: true, registered };
113
- } catch (e) {
114
- const error = e.message;
115
- spinner.warn(`Site import failed: ${error}. Re-run to retry.`);
116
- return { ok: false, registered: [], error };
117
- }
118
- }
119
-
120
- export {
121
- waitForApiHealth,
122
- waitForEdgeRunning,
123
- importMigratedSites
124
- };