@slicemedia/devkit-cli 0.0.0-bootstrap.0 → 0.1.1

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 (51) hide show
  1. package/README.md +46 -3
  2. package/bin/slicemedia-devkit.js +2 -0
  3. package/dist/args.d.ts +10 -0
  4. package/dist/args.d.ts.map +1 -0
  5. package/dist/args.js +48 -0
  6. package/dist/args.js.map +1 -0
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +4 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/build.d.ts +19 -0
  12. package/dist/build.d.ts.map +1 -0
  13. package/dist/build.js +73 -0
  14. package/dist/build.js.map +1 -0
  15. package/dist/commands.d.ts +18 -0
  16. package/dist/commands.d.ts.map +1 -0
  17. package/dist/commands.js +286 -0
  18. package/dist/commands.js.map +1 -0
  19. package/dist/dev.d.ts +8 -0
  20. package/dist/dev.d.ts.map +1 -0
  21. package/dist/dev.js +20 -0
  22. package/dist/dev.js.map +1 -0
  23. package/dist/discovery.d.ts +3 -0
  24. package/dist/discovery.d.ts.map +1 -0
  25. package/dist/discovery.js +216 -0
  26. package/dist/discovery.js.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +7 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/output.d.ts +8 -0
  32. package/dist/output.d.ts.map +1 -0
  33. package/dist/output.js +28 -0
  34. package/dist/output.js.map +1 -0
  35. package/dist/sanitize.d.ts +22 -0
  36. package/dist/sanitize.d.ts.map +1 -0
  37. package/dist/sanitize.js +342 -0
  38. package/dist/sanitize.js.map +1 -0
  39. package/dist/types.d.ts +20 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +2 -0
  42. package/dist/types.js.map +1 -0
  43. package/dist/webflow/client.d.ts +75 -0
  44. package/dist/webflow/client.d.ts.map +1 -0
  45. package/dist/webflow/client.js +186 -0
  46. package/dist/webflow/client.js.map +1 -0
  47. package/dist/webflow/scan.d.ts +17 -0
  48. package/dist/webflow/scan.d.ts.map +1 -0
  49. package/dist/webflow/scan.js +51 -0
  50. package/dist/webflow/scan.js.map +1 -0
  51. package/package.json +48 -8
@@ -0,0 +1,186 @@
1
+ export class WebflowHttpError extends Error {
2
+ status;
3
+ responseBody;
4
+ responseReceived = true;
5
+ constructor(status, responseBody) {
6
+ super(`Webflow API request failed with HTTP ${status}.`);
7
+ this.name = "WebflowHttpError";
8
+ this.status = status;
9
+ this.responseBody = responseBody;
10
+ }
11
+ }
12
+ export class WebflowClient {
13
+ #token;
14
+ #baseUrl;
15
+ #fetch;
16
+ #retries;
17
+ #sleep;
18
+ constructor(options = {}) {
19
+ this.#token = options.token ?? webflowTokenFromEnvironment();
20
+ const configuredBaseUrl = options.baseUrl ?? "https://api.webflow.com/v2";
21
+ let baseUrlEnd = configuredBaseUrl.length;
22
+ while (baseUrlEnd > 0 && configuredBaseUrl[baseUrlEnd - 1] === "/")
23
+ baseUrlEnd -= 1;
24
+ this.#baseUrl = configuredBaseUrl.slice(0, baseUrlEnd);
25
+ this.#fetch = options.fetch ?? fetch;
26
+ this.#retries = options.retries ?? 4;
27
+ this.#sleep = options.sleep ?? delay;
28
+ }
29
+ async #request(resource) {
30
+ const url = resource.startsWith("http")
31
+ ? resource
32
+ : `${this.#baseUrl}/${resource.replace(/^\/+/, "")}`;
33
+ for (let attempt = 0;; attempt += 1) {
34
+ const headers = new Headers();
35
+ headers.set("Authorization", `Bearer ${this.#token}`);
36
+ headers.set("Accept", "application/json");
37
+ let response;
38
+ try {
39
+ response = await this.#fetch(url, { method: "GET", headers });
40
+ }
41
+ catch (error) {
42
+ if (attempt >= this.#retries)
43
+ throw error;
44
+ await this.#sleep(retryDelay(null, attempt));
45
+ continue;
46
+ }
47
+ const responseBody = await parseResponseBody(response);
48
+ if (response.ok)
49
+ return responseBody;
50
+ if (!isRetryable(response.status) || attempt >= this.#retries) {
51
+ throw new WebflowHttpError(response.status, responseBody);
52
+ }
53
+ await this.#sleep(retryDelay(response.headers.get("retry-after"), attempt));
54
+ }
55
+ }
56
+ async #paginate(resource, selectItems) {
57
+ const requestedLimit = 100;
58
+ const collected = [];
59
+ let offset = 0;
60
+ let cursor;
61
+ const visited = new Set();
62
+ for (;;) {
63
+ const requestUrl = resource.startsWith("http")
64
+ ? new URL(resource)
65
+ : new URL(`${this.#baseUrl}/${resource.replace(/^\/+/, "")}`);
66
+ requestUrl.searchParams.set("limit", String(requestedLimit));
67
+ if (cursor !== undefined)
68
+ requestUrl.searchParams.set("cursor", cursor);
69
+ else
70
+ requestUrl.searchParams.set("offset", String(offset));
71
+ const page = await this.#request(requestUrl.toString());
72
+ const items = selectItems(page);
73
+ collected.push(...items);
74
+ const pagination = page.pagination;
75
+ const pageOffset = paginationInteger(pagination?.offset, "offset", offset, true);
76
+ const limit = paginationInteger(pagination?.limit, "limit", requestedLimit, false);
77
+ const total = paginationInteger(pagination?.total, "total", undefined, true);
78
+ if (limit > requestedLimit) {
79
+ throw new Error(`Webflow pagination returned limit ${limit} above ${requestedLimit}.`);
80
+ }
81
+ if (items.length > limit) {
82
+ throw new Error("Webflow pagination returned more items than its declared limit.");
83
+ }
84
+ if (cursor === undefined && pageOffset !== offset) {
85
+ throw new Error("Webflow pagination returned an unexpected offset.");
86
+ }
87
+ if (pagination?.next !== undefined && pagination.next !== null && pagination.next !== "") {
88
+ if (visited.has(pagination.next))
89
+ throw new Error("Webflow pagination returned a repeated cursor.");
90
+ visited.add(pagination.next);
91
+ cursor = pagination.next;
92
+ continue;
93
+ }
94
+ if (total === undefined) {
95
+ if (limit > 0 && items.length >= limit) {
96
+ throw new Error("Webflow pagination returned a full page without a next cursor or total count.");
97
+ }
98
+ break;
99
+ }
100
+ const consumedOffset = pageOffset + items.length;
101
+ if (consumedOffset > total) {
102
+ throw new Error("Webflow pagination returned more items than its total count.");
103
+ }
104
+ if (consumedOffset === total)
105
+ break;
106
+ if (items.length === 0 || items.length < limit) {
107
+ throw new Error("Webflow pagination ended before its declared total count.");
108
+ }
109
+ offset = consumedOffset;
110
+ }
111
+ return collected;
112
+ }
113
+ listComponents(siteId) {
114
+ return this.#paginate(`/sites/${encodeURIComponent(siteId)}/components`, (page) => page.components ?? []);
115
+ }
116
+ getSite(siteId) {
117
+ return this.#request(`/sites/${encodeURIComponent(siteId)}`);
118
+ }
119
+ listComponentProperties(siteId, componentId) {
120
+ return this.#paginate(`/sites/${encodeURIComponent(siteId)}/components/${encodeURIComponent(componentId)}/properties`, (page) => page.properties ?? page.componentProperties ?? []);
121
+ }
122
+ listRegisteredScripts(siteId) {
123
+ return this.#paginate(`/sites/${encodeURIComponent(siteId)}/registered_scripts`, (page) => page.registeredScripts ?? page.scripts ?? []);
124
+ }
125
+ async getCustomCode(siteId) {
126
+ const response = await this.#request(`/sites/${encodeURIComponent(siteId)}/custom_code`);
127
+ return {
128
+ scripts: response.scripts ?? [],
129
+ ...(typeof response.createdOn === "string" ? { createdOn: response.createdOn } : {}),
130
+ ...(typeof response.lastUpdated === "string" ? { lastUpdated: response.lastUpdated } : {}),
131
+ };
132
+ }
133
+ }
134
+ function paginationInteger(value, name, fallback, allowZero) {
135
+ if (value === undefined)
136
+ return fallback;
137
+ if (!Number.isSafeInteger(value) || value < 0 || (!allowZero && value === 0)) {
138
+ throw new Error(`Webflow pagination returned invalid ${name}.`);
139
+ }
140
+ return value;
141
+ }
142
+ export function webflowTokenFromEnvironment(env = process.env) {
143
+ const token = env.WEBFLOW_OAUTH_ACCESS_TOKEN ?? env.WEBFLOW_OAUTH_TOKEN ?? env.WEBFLOW_API_TOKEN;
144
+ if (token === undefined || token.trim() === "") {
145
+ throw new Error("Set WEBFLOW_OAUTH_ACCESS_TOKEN or WEBFLOW_API_TOKEN before using Webflow API commands.");
146
+ }
147
+ return token;
148
+ }
149
+ export function webflowOAuthTokenFromEnvironment(env = process.env) {
150
+ const token = env.WEBFLOW_OAUTH_ACCESS_TOKEN ?? env.WEBFLOW_OAUTH_TOKEN;
151
+ if (token === undefined || token.trim() === "") {
152
+ throw new Error("Set WEBFLOW_OAUTH_ACCESS_TOKEN before inspecting Webflow custom code; API, site, and workspace tokens cannot access custom code.");
153
+ }
154
+ return token;
155
+ }
156
+ async function parseResponseBody(response) {
157
+ const body = await response.text();
158
+ if (body === "")
159
+ return undefined;
160
+ try {
161
+ return JSON.parse(body);
162
+ }
163
+ catch {
164
+ return body;
165
+ }
166
+ }
167
+ function isRetryable(status) {
168
+ if (status === 429)
169
+ return true;
170
+ return status === 500 || status === 502 || status === 503 || status === 504;
171
+ }
172
+ function retryDelay(retryAfter, attempt) {
173
+ if (retryAfter !== null) {
174
+ const seconds = Number(retryAfter);
175
+ if (Number.isFinite(seconds) && seconds >= 0)
176
+ return Math.min(seconds * 1000, 30_000);
177
+ const date = Date.parse(retryAfter);
178
+ if (Number.isFinite(date))
179
+ return Math.max(0, Math.min(date - Date.now(), 30_000));
180
+ }
181
+ return Math.min(250 * 2 ** attempt, 4_000);
182
+ }
183
+ function delay(milliseconds) {
184
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
185
+ }
186
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/webflow/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { AppliedScript, RegisteredScript, WebflowClient } from "./client.js";
2
+ export interface RenderedScript {
3
+ readonly source?: string;
4
+ readonly integrity?: string;
5
+ readonly type?: string;
6
+ readonly async: boolean;
7
+ readonly defer: boolean;
8
+ }
9
+ export interface ApiScriptScan {
10
+ readonly registered: readonly RegisteredScript[];
11
+ readonly applied: readonly AppliedScript[];
12
+ readonly orphanedAppliedIds: readonly string[];
13
+ }
14
+ export declare function scanRenderedScripts(pageUrl: string, fetcher?: typeof fetch): Promise<readonly RenderedScript[]>;
15
+ export declare function parseRenderedScripts(html: string): readonly RenderedScript[];
16
+ export declare function scanApiScripts(client: WebflowClient, siteId: string): Promise<ApiScriptScan>;
17
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/webflow/scan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAElF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;CAChD;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAQpC;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,cAAc,EAAE,CAiB5E;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CAaxB"}
@@ -0,0 +1,51 @@
1
+ export async function scanRenderedScripts(pageUrl, fetcher = fetch) {
2
+ const url = new URL(pageUrl);
3
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
4
+ throw new Error("--url must use HTTP or HTTPS.");
5
+ }
6
+ const response = await fetcher(url, { headers: { Accept: "text/html" } });
7
+ if (!response.ok)
8
+ throw new Error(`Page scan failed with HTTP ${response.status}.`);
9
+ return parseRenderedScripts(await response.text());
10
+ }
11
+ export function parseRenderedScripts(html) {
12
+ const scripts = [];
13
+ const scriptPattern = /<script\b([^>]*)>/giu;
14
+ for (const match of html.matchAll(scriptPattern)) {
15
+ const attributes = match[1] ?? "";
16
+ const source = readAttribute(attributes, "src");
17
+ const integrity = readAttribute(attributes, "integrity");
18
+ const type = readAttribute(attributes, "type");
19
+ scripts.push({
20
+ ...(source === undefined ? {} : { source }),
21
+ ...(integrity === undefined ? {} : { integrity }),
22
+ ...(type === undefined ? {} : { type }),
23
+ async: hasAttribute(attributes, "async"),
24
+ defer: hasAttribute(attributes, "defer"),
25
+ });
26
+ }
27
+ return scripts;
28
+ }
29
+ export async function scanApiScripts(client, siteId) {
30
+ const [registered, customCode] = await Promise.all([
31
+ client.listRegisteredScripts(siteId),
32
+ client.getCustomCode(siteId),
33
+ ]);
34
+ const registeredIds = new Set(registered.map((script) => script.id));
35
+ return {
36
+ registered,
37
+ applied: customCode.scripts,
38
+ orphanedAppliedIds: customCode.scripts
39
+ .filter((script) => !registeredIds.has(script.id))
40
+ .map((script) => script.id),
41
+ };
42
+ }
43
+ function readAttribute(attributes, name) {
44
+ const expression = new RegExp(`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`, "iu");
45
+ const match = expression.exec(attributes);
46
+ return match?.[1] ?? match?.[2] ?? match?.[3];
47
+ }
48
+ function hasAttribute(attributes, name) {
49
+ return new RegExp(`(?:^|\\s)${name}(?:\\s|=|$)`, "iu").test(attributes);
50
+ }
51
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/webflow/scan.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,20 +1,60 @@
1
1
  {
2
2
  "name": "@slicemedia/devkit-cli",
3
- "version": "0.0.0-bootstrap.0",
4
- "description": "Bootstrap placeholder for the @slicemedia/devkit-cli package identity; not a functional release.",
3
+ "version": "0.1.1",
5
4
  "private": false,
6
- "license": "MIT",
5
+ "description": "Build local project bundles and inspect Webflow state with Slice Media DevKit.",
7
6
  "author": "Slice Media",
8
- "files": ["README.md", "LICENSE"],
9
7
  "repository": {
10
8
  "type": "git",
11
- "url": "git+https://github.com/slicemedia/devkit.git"
9
+ "url": "git+https://github.com/slicemedia/devkit.git",
10
+ "directory": "packages/cli"
12
11
  },
13
- "homepage": "https://github.com/slicemedia/devkit#readme",
12
+ "homepage": "https://github.com/slicemedia/devkit/tree/main/packages/cli#readme",
14
13
  "bugs": {
15
14
  "url": "https://github.com/slicemedia/devkit/issues"
16
15
  },
16
+ "keywords": [
17
+ "slicemedia",
18
+ "webflow",
19
+ "cli",
20
+ "vite",
21
+ "typescript"
22
+ ],
23
+ "license": "MIT",
24
+ "type": "module",
25
+ "bin": {
26
+ "slicemedia-devkit": "./bin/slicemedia-devkit.js"
27
+ },
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ }
33
+ },
34
+ "files": [
35
+ "bin",
36
+ "dist",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "engines": {
41
+ "node": ">=22.13.0 <23 || >=24.0.0 <25"
42
+ },
43
+ "dependencies": {
44
+ "vite": "^8.2.1"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^22.20.1",
48
+ "typescript": "6.0.3",
49
+ "vitest": "^4.1.10"
50
+ },
17
51
  "publishConfig": {
18
- "access": "public"
52
+ "access": "public",
53
+ "provenance": true
54
+ },
55
+ "scripts": {
56
+ "build": "node scripts/prepare-build.mjs && tsc -p tsconfig.build.json && node scripts/finalize-build.mjs",
57
+ "test": "vitest run src",
58
+ "typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.test.json"
19
59
  }
20
- }
60
+ }