@theholocron/holocron-plugin-vercel 5.0.0-alpha.20 → 5.0.0-alpha.200

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -55,10 +55,39 @@ Capability covers:
55
55
  - `updateProjectSettings()` — toggle preview deploys, git-creates-deploys
56
56
  - `setEnvVar()` / `listEnvVars()` — per-target env vars
57
57
  - `triggerDeployment()` — branch deploys with optional named target
58
+ (requires a project already linked to a Git repo)
59
+ - `deployFunction()` — deploy directly from source files, bypassing Git
60
+ entirely: `POST /v13/deployments` with an inline `files` array, no
61
+ linked repo required. For a consumer with no repo to deploy from — a
62
+ webhook receiver shipped as an npm package, for instance. Always
63
+ deploys with `projectSettings.framework: null` (a bare function, not
64
+ an app) — `defaultFramework` only applies to `ensureProject()`'s
65
+ Git-linked path.
58
66
  - `getDeployment()` — fetch a deployment by id
67
+ - `ensureCustomDomain()` — idempotent add (list → add-if-missing →
68
+ check DNS routing). Ownership (`verified`) and DNS routing are
69
+ separate: once a team already owns a domain's apex, every new
70
+ subdomain auto-verifies immediately with no fresh challenge, so
71
+ attachment alone can't tell you whether traffic is actually routed
72
+ to Vercel yet. `domains.config()` answers that regardless of
73
+ ownership state, returning a per-project CNAME target — never a
74
+ fixed well-known host — only when DNS isn't already configured. The
75
+ returned DNS record is handed to the configured `dns` provider by
76
+ `holocron repo setup`.
77
+
78
+ Declare the production domain in the Vercel provider options. On `holocron repo setup`,
79
+ the domain is attached to the project and any Vercel verification CNAME is
80
+ upserted through the configured DNS provider:
81
+
82
+ ```ts
83
+ providers: {
84
+ deployment: ["vercel", { teamId: "team_…", domain: "sentinel.example.com" }],
85
+ dns: "cloudflare",
86
+ }
87
+ ```
59
88
 
60
89
  Out of scope for alpha.0 (file a follow-up if needed):
61
90
 
62
- - Domain management (`addDomain` / `removeDomain`)
91
+ - Domain removal (`removeDomain`)
63
92
  - Deletion (`deleteProject`)
64
93
  - Marketplace integrations (e.g. `vercel install neon` for vault-managed databases)
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { AuthError, Deployment, DeploymentProject, DeploymentProjectSettings, DeploymentRecord, DeploymentTarget, DeploymentTrigger, ResolveTokenInput } from "@theholocron/cli";
1
+ import { AuthError, DeployFunctionConfig, DeployFunctionResult, Deployment, DeploymentProject, DeploymentProjectSettings, DeploymentRecord, DeploymentTarget, DeploymentTrigger, DnsRecordRequest, ResolveTokenInput, VerifyTokenFailure, VerifyTokenResult, VerifyTokenResult as VerifyTokenResult$1, VerifyTokenSuccess } from "@theholocron/cli";
2
2
  import { VercelClient, VercelClient as VercelClient$1, VercelClientOptions, createVercelClient } from "@theholocron/vercel-client";
3
3
  //#region src/auth.d.ts
4
4
  declare const resolveToken: (input?: ResolveTokenInput) => string;
@@ -7,11 +7,14 @@ declare const resolveToken: (input?: ResolveTokenInput) => string;
7
7
  interface DeploymentOptions {
8
8
  /** Optional framework hint passed to project creates. Defaults to "nextjs". */
9
9
  defaultFramework?: string;
10
+ /** Custom domain that `holocron repo setup` should attach to this project. */
11
+ domain?: string;
10
12
  }
11
13
  declare class VercelDeployment implements Deployment {
12
14
  private readonly client;
13
15
  readonly key: "deployment";
14
16
  readonly providerName = "vercel";
17
+ readonly domain?: string;
15
18
  private readonly defaultFramework;
16
19
  constructor(client: () => VercelClient$1, opts?: DeploymentOptions);
17
20
  listProjects(): Promise<DeploymentProject[]>;
@@ -30,29 +33,36 @@ declare class VercelDeployment implements Deployment {
30
33
  target?: DeploymentTrigger;
31
34
  }): Promise<DeploymentRecord>;
32
35
  getDeployment(deploymentId: string): Promise<DeploymentRecord>;
36
+ deployFunction(projectId: string, config: DeployFunctionConfig): Promise<DeployFunctionResult>;
37
+ /**
38
+ * Idempotent — matches `Deployment.ensureCustomDomain`'s contract
39
+ * (never break on re-runs, per CLAUDE.md's probe-then-act standard).
40
+ *
41
+ * Ownership (`domains.add`'s `verified`) and DNS routing are separate
42
+ * concerns: once a team already owns the domain's apex (true for any
43
+ * org with more than one project on the same domain), every new
44
+ * subdomain auto-verifies immediately with no `verification`
45
+ * challenge — re-adding an already-attached domain returns 409, not
46
+ * a fresh one. So attachment alone can't tell us whether traffic is
47
+ * actually routed to Vercel yet. `domains.config()` (Vercel's DNS
48
+ * *configuration* check) answers that regardless of ownership state:
49
+ * `misconfigured` + a `recommendedCNAME`, per-project, never a fixed
50
+ * well-known host — always read it from this response, never
51
+ * hardcode it. Returned as a `DnsRecordRequest` — the caller (e.g.
52
+ * `holocron repo setup`'s custom-domain step) hands it straight to
53
+ * `dns.upsertRecord()`, same as `Wiki.dnsRecord()` already does for
54
+ * the wiki's own domain.
55
+ */
56
+ ensureCustomDomain(projectId: string, hostname: string): Promise<DnsRecordRequest | null>;
33
57
  private getProjectByName;
34
58
  }
35
59
  //#endregion
36
60
  //#region src/verify-token.d.ts
37
- /**
38
- * `verifyToken` — plugin-level export used by `holocron auth set` +
39
- * `holocron auth check`. Hits `GET /v2/user` and translates the
40
- * response into the normalized `VerifyTokenResult` shape.
41
- */
42
- interface VerifyTokenSuccess {
43
- ok: true;
44
- subject: string;
45
- }
46
- interface VerifyTokenFailure {
47
- ok: false;
48
- message: string;
49
- }
50
- type VerifyTokenResult = VerifyTokenSuccess | VerifyTokenFailure;
51
61
  interface VerifyTokenOptions {
52
62
  baseUrl?: string;
53
63
  fetch?: typeof fetch;
54
64
  }
55
- declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult>;
65
+ declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult$1>;
56
66
  //#endregion
57
67
  //#region src/index.d.ts
58
68
  interface VercelPluginOptions extends ResolveTokenInput {
@@ -60,6 +70,8 @@ interface VercelPluginOptions extends ResolveTokenInput {
60
70
  teamId?: string;
61
71
  /** Default framework slug for new project creates. Defaults to "nextjs". */
62
72
  defaultFramework?: string;
73
+ /** Custom domain that `holocron repo setup` should attach to the Vercel project. */
74
+ domain?: string;
63
75
  /** Override base URL for tests. */
64
76
  baseUrl?: string;
65
77
  /** Override `fetch` for tests. */
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { AuthError, ProviderApiError, createResolveToken } from "@theholocron/cli";
2
2
  import { createVercelClient } from "@theholocron/vercel-client";
3
+ import { errorMessage } from "@theholocron/misc-utils";
3
4
  //#region src/auth.ts
4
5
  const resolveToken = createResolveToken({
5
6
  envName: "HOLOCRON_VERCEL_TOKEN",
@@ -13,10 +14,12 @@ var VercelDeployment = class {
13
14
  client;
14
15
  key = "deployment";
15
16
  providerName = "vercel";
17
+ domain;
16
18
  defaultFramework;
17
19
  constructor(client, opts = {}) {
18
20
  this.client = client;
19
21
  this.defaultFramework = opts.defaultFramework ?? "nextjs";
22
+ this.domain = opts.domain;
20
23
  }
21
24
  async listProjects() {
22
25
  const { projects } = await this.client().projects.list();
@@ -60,6 +63,64 @@ var VercelDeployment = class {
60
63
  const raw = await this.client().deployments.get(deploymentId);
61
64
  return mapDeployment(raw, raw.meta?.githubCommitRef ?? null);
62
65
  }
66
+ async deployFunction(projectId, config) {
67
+ const raw = await this.client().deployments.create({
68
+ projectName: projectId,
69
+ files: Object.entries(config.files).map(([file, content]) => ({
70
+ file,
71
+ content
72
+ })),
73
+ framework: null,
74
+ target: config.target
75
+ });
76
+ return {
77
+ deploymentId: raw.id,
78
+ url: raw.url
79
+ };
80
+ }
81
+ /**
82
+ * Idempotent — matches `Deployment.ensureCustomDomain`'s contract
83
+ * (never break on re-runs, per CLAUDE.md's probe-then-act standard).
84
+ *
85
+ * Ownership (`domains.add`'s `verified`) and DNS routing are separate
86
+ * concerns: once a team already owns the domain's apex (true for any
87
+ * org with more than one project on the same domain), every new
88
+ * subdomain auto-verifies immediately with no `verification`
89
+ * challenge — re-adding an already-attached domain returns 409, not
90
+ * a fresh one. So attachment alone can't tell us whether traffic is
91
+ * actually routed to Vercel yet. `domains.config()` (Vercel's DNS
92
+ * *configuration* check) answers that regardless of ownership state:
93
+ * `misconfigured` + a `recommendedCNAME`, per-project, never a fixed
94
+ * well-known host — always read it from this response, never
95
+ * hardcode it. Returned as a `DnsRecordRequest` — the caller (e.g.
96
+ * `holocron repo setup`'s custom-domain step) hands it straight to
97
+ * `dns.upsertRecord()`, same as `Wiki.dnsRecord()` already does for
98
+ * the wiki's own domain.
99
+ */
100
+ async ensureCustomDomain(projectId, hostname) {
101
+ const { domains: existing } = await this.client().domains.list(projectId);
102
+ let apexName = existing.find((d) => d.name === hostname)?.apexName;
103
+ if (!apexName) try {
104
+ apexName = (await this.client().domains.add(projectId, hostname)).apexName;
105
+ } catch (err) {
106
+ if (!(err instanceof ProviderApiError && err.status === 409)) throw err;
107
+ const { domains: refreshed } = await this.client().domains.list(projectId);
108
+ apexName = refreshed.find((d) => d.name === hostname)?.apexName;
109
+ }
110
+ if (!apexName) return null;
111
+ const config = await this.client().domains.config(hostname, projectId);
112
+ if (!config.misconfigured) return null;
113
+ const cname = config.recommendedCNAME[0]?.value;
114
+ if (!cname) return null;
115
+ return {
116
+ zone: apexName,
117
+ record: {
118
+ type: "CNAME",
119
+ name: hostname,
120
+ content: cname
121
+ }
122
+ };
123
+ }
63
124
  async getProjectByName(name) {
64
125
  try {
65
126
  return mapProject(await this.client().projects.get(name));
@@ -87,6 +148,7 @@ function mapDeployment(raw, branch) {
87
148
  status: normalizeState(raw.readyState)
88
149
  };
89
150
  if (raw.target) record.target = raw.target;
151
+ if (raw.errorMessage) record.errorMessage = raw.errorMessage;
90
152
  return record;
91
153
  }
92
154
  function normalizeState(s) {
@@ -101,11 +163,6 @@ function normalizeState(s) {
101
163
  }
102
164
  //#endregion
103
165
  //#region src/verify-token.ts
104
- /**
105
- * `verifyToken` — plugin-level export used by `holocron auth set` +
106
- * `holocron auth check`. Hits `GET /v2/user` and translates the
107
- * response into the normalized `VerifyTokenResult` shape.
108
- */
109
166
  async function verifyToken(token, opts = {}) {
110
167
  const client = createVercelClient({
111
168
  token,
@@ -121,7 +178,7 @@ async function verifyToken(token, opts = {}) {
121
178
  } catch (err) {
122
179
  return {
123
180
  ok: false,
124
- message: err instanceof Error ? err.message : String(err)
181
+ message: errorMessage(err)
125
182
  };
126
183
  }
127
184
  }
@@ -142,6 +199,7 @@ function createContext(options = {}) {
142
199
  function deployment(ctx) {
143
200
  const opts = {};
144
201
  if (ctx.options.defaultFramework !== void 0) opts.defaultFramework = ctx.options.defaultFramework;
202
+ if (ctx.options.domain !== void 0) opts.domain = ctx.options.domain;
145
203
  return new VercelDeployment(ctx.client, opts);
146
204
  }
147
205
  function createPlugin(options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/holocron-plugin-vercel",
3
- "version": "5.0.0-alpha.20",
3
+ "version": "5.0.0-alpha.200",
4
4
  "description": "Holocron plugin for Vercel. Implements the deployment capability against the Vercel REST API.",
5
5
  "keywords": [
6
6
  "deployment",
@@ -8,12 +8,12 @@
8
8
  "plugin",
9
9
  "vercel"
10
10
  ],
11
- "homepage": "https://github.com/theholocron/holocron/tree/main/packages/holocron-plugin-vercel#readme",
11
+ "homepage": "https://github.com/theholocron/holocron/tree/main/plugins/holocron-plugin-vercel#readme",
12
12
  "bugs": "https://github.com/theholocron/holocron/issues",
13
13
  "repository": {
14
14
  "type": "git",
15
15
  "url": "git+https://github.com/theholocron/holocron.git",
16
- "directory": "packages/holocron-plugin-vercel"
16
+ "directory": "plugins/holocron-plugin-vercel"
17
17
  },
18
18
  "license": "MIT",
19
19
  "author": "Newton Koumantzelis",
@@ -30,12 +30,13 @@
30
30
  "dist"
31
31
  ],
32
32
  "devDependencies": {
33
- "@theholocron/eslint-config": "^8.0.0",
34
- "@theholocron/http-client": "^1.20.0",
35
- "@theholocron/tsconfig": "^8.0.0",
36
- "@theholocron/tsdown-config": "^8.0.0",
37
- "@theholocron/vercel-client": "^1.20.0",
38
- "@theholocron/vitest-config": "^8.0.0",
33
+ "@theholocron/eslint-config": "^8.8.2",
34
+ "@theholocron/http-client": "^1.43.1",
35
+ "@theholocron/misc-utils": "^1.16.0",
36
+ "@theholocron/tsconfig": "^8.8.2",
37
+ "@theholocron/tsdown-config": "^8.8.2",
38
+ "@theholocron/vercel-client": "^1.43.1",
39
+ "@theholocron/vitest-config": "^8.8.2",
39
40
  "@types/node": "^26",
40
41
  "@vitest/coverage-v8": "^4.1.11",
41
42
  "@vitest/eslint-plugin": "^1.6.27",
@@ -43,14 +44,15 @@
43
44
  "eslint-plugin-n": "^18.3.0",
44
45
  "globals": "^17.11.0",
45
46
  "tsdown": "^0.22.14",
46
- "tsx": "4.23.12",
47
+ "tsx": "4.23.15",
47
48
  "typescript": "^5.9.3",
48
49
  "vitest": "^4.1.11",
49
- "@theholocron/cli": "5.0.0-alpha.20"
50
+ "@theholocron/cli": "5.0.0-alpha.200"
50
51
  },
51
52
  "peerDependencies": {
52
- "@theholocron/vercel-client": "^1.20.0",
53
- "@theholocron/cli": "5.0.0-alpha.20"
53
+ "@theholocron/misc-utils": "^1.16.0",
54
+ "@theholocron/vercel-client": "^1.43.1",
55
+ "@theholocron/cli": "5.0.0-alpha.200"
54
56
  },
55
57
  "peerDependenciesMeta": {
56
58
  "@theholocron/vercel-client": {}