@stacksjs/browser-extension 0.70.147 → 0.70.149
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 +2 -1
- package/dist/app-store-connect.d.ts +3 -0
- package/dist/app-store-connect.js +34 -4
- package/dist/build.js +2 -2
- package/dist/chrome-web-store.d.ts +18 -1
- package/dist/chrome-web-store.js +29 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/safari.d.ts +2 -0
- package/dist/safari.js +23 -5
- package/dist/scaffold.d.ts +22 -0
- package/dist/scaffold.js +92 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,8 @@ packaging owned by the framework.
|
|
|
11
11
|
## Quick start
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
buddy extension:init # scaffold
|
|
14
|
+
buddy extension:init # scaffold Chrome + Firefox + Safari, including the Xcode app
|
|
15
|
+
buddy extension:init --target safari --name "My Extension" --bundle-id com.example.MyExtension
|
|
15
16
|
buddy extension:build # build all targets → dist/ (+ dist-firefox/)
|
|
16
17
|
buddy extension:build --target chrome
|
|
17
18
|
buddy extension:build --target safari # → dist-safari/ (browser.* namespace, safari manifest)
|
|
@@ -61,6 +61,9 @@ export declare interface SafariAppStoreVersionResult {
|
|
|
61
61
|
created: boolean
|
|
62
62
|
updated: boolean
|
|
63
63
|
id: string
|
|
64
|
+
status?: 'ready' | 'deferred' | 'published'
|
|
65
|
+
appStoreState?: string
|
|
66
|
+
reason?: string
|
|
64
67
|
}
|
|
65
68
|
export declare interface SafariBuildAttachmentResult {
|
|
66
69
|
platform: SafariPlatform
|
|
@@ -153,7 +153,13 @@ const editableVersionStates = new Set([
|
|
|
153
153
|
"PREPARE_FOR_SUBMISSION",
|
|
154
154
|
"DEVELOPER_REJECTED",
|
|
155
155
|
"REJECTED",
|
|
156
|
-
"METADATA_REJECTED"
|
|
156
|
+
"METADATA_REJECTED",
|
|
157
|
+
"INVALID_BINARY"
|
|
158
|
+
]), releasedVersionStates = new Set([
|
|
159
|
+
"READY_FOR_DISTRIBUTION",
|
|
160
|
+
"READY_FOR_SALE",
|
|
161
|
+
"DEVELOPER_REMOVED_FROM_SALE",
|
|
162
|
+
"REMOVED_FROM_SALE"
|
|
157
163
|
]);
|
|
158
164
|
function appStorePlatform(platform) {
|
|
159
165
|
return platform === "ios" ? "IOS" : "MAC_OS";
|
|
@@ -194,19 +200,43 @@ async function ensureConfiguredAppStoreVersions(client, appId, platforms, versio
|
|
|
194
200
|
for (const platform of [...new Set(platforms)]) {
|
|
195
201
|
const applePlatform = appStorePlatform(platform), exact = versions.find((item) => item.attributes.platform === applePlatform && item.attributes.versionString === version);
|
|
196
202
|
if (exact) {
|
|
197
|
-
|
|
203
|
+
const appStoreState = exact.attributes.appStoreState, status = editableVersionStates.has(appStoreState) ? "ready" : releasedVersionStates.has(appStoreState) ? "published" : "deferred";
|
|
204
|
+
results.push({
|
|
205
|
+
platform,
|
|
206
|
+
version,
|
|
207
|
+
created: !1,
|
|
208
|
+
updated: !1,
|
|
209
|
+
id: exact.id,
|
|
210
|
+
status,
|
|
211
|
+
appStoreState,
|
|
212
|
+
...status === "deferred" ? { reason: `Safari ${platform} version ${version} is already ${appStoreState}` } : {}
|
|
213
|
+
});
|
|
198
214
|
continue;
|
|
199
215
|
}
|
|
200
216
|
const editable = versions.find((item) => item.attributes.platform === applePlatform && editableVersionStates.has(item.attributes.appStoreState));
|
|
201
217
|
if (editable) {
|
|
202
218
|
const updated = await client.updateAppStoreVersion(editable.id, version);
|
|
203
219
|
editable.attributes.versionString = version;
|
|
204
|
-
results.push({ platform, version, created: !1, updated: !0, id: updated.id });
|
|
220
|
+
results.push({ platform, version, created: !1, updated: !0, id: updated.id, status: "ready", appStoreState: updated.attributes.appStoreState });
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
const blocking = versions.find((item) => item.attributes.platform === applePlatform && !releasedVersionStates.has(item.attributes.appStoreState));
|
|
224
|
+
if (blocking) {
|
|
225
|
+
results.push({
|
|
226
|
+
platform,
|
|
227
|
+
version,
|
|
228
|
+
created: !1,
|
|
229
|
+
updated: !1,
|
|
230
|
+
id: blocking.id,
|
|
231
|
+
status: "deferred",
|
|
232
|
+
appStoreState: blocking.attributes.appStoreState,
|
|
233
|
+
reason: `Safari ${platform} version ${version} is queued behind ${blocking.attributes.versionString} (${blocking.attributes.appStoreState})`
|
|
234
|
+
});
|
|
205
235
|
continue;
|
|
206
236
|
}
|
|
207
237
|
const created = await client.createAppStoreVersion(appId, applePlatform, version);
|
|
208
238
|
versions.push(created);
|
|
209
|
-
results.push({ platform, version, created: !0, updated: !1, id: created.id });
|
|
239
|
+
results.push({ platform, version, created: !0, updated: !1, id: created.id, status: "ready", appStoreState: created.attributes.appStoreState });
|
|
210
240
|
}
|
|
211
241
|
return results;
|
|
212
242
|
}
|
package/dist/build.js
CHANGED
|
@@ -69,12 +69,12 @@ export async function buildExtension(config, options) {
|
|
|
69
69
|
const pages = pageEntries(config.pages);
|
|
70
70
|
await Promise.all(pages.filter((p) => p.page.script).map((p) => buildScript(p.page.script, `${p.name}.js`, outdir, cwd, minify)));
|
|
71
71
|
if (pages.length) {
|
|
72
|
-
const { default: stxPlugin } = await import("bun-plugin-stx"), result = await Bun.build({
|
|
72
|
+
const { default: stxPlugin } = await import("bun-plugin-stx"), resourcesPartials = resolve(cwd, "resources/partials"), legacyPartials = resolve(cwd, "partials"), partialsDir = existsSync(resourcesPartials) ? resourcesPartials : legacyPartials, result = await Bun.build({
|
|
73
73
|
entrypoints: pages.map((p) => resolve(cwd, p.page.template)),
|
|
74
74
|
outdir,
|
|
75
75
|
minify,
|
|
76
76
|
naming: { entry: "[name].html" },
|
|
77
|
-
plugins: [stxPlugin()]
|
|
77
|
+
plugins: [stxPlugin({ partialsDir })]
|
|
78
78
|
});
|
|
79
79
|
if (!result.success)
|
|
80
80
|
throw Error(`[browser-extension] failed to build pages: ${result.logs.join(`
|
|
@@ -2,7 +2,7 @@ import type { ChromeWebStoreConfig, ExtensionConfig } from './types';
|
|
|
2
2
|
/** Build the RS256 assertion Google exchanges for a short-lived OAuth token. */
|
|
3
3
|
export declare function chromeWebStoreServiceAccountAssertion(serviceAccount: GoogleServiceAccount, now?: unknown): string;
|
|
4
4
|
/** Build, package, upload, and optionally submit an existing Chrome Web Store item. */
|
|
5
|
-
export declare function publishChromeExtension(config: ExtensionConfig, options: ChromeWebStorePublishOptions): Promise<
|
|
5
|
+
export declare function publishChromeExtension(config: ExtensionConfig, options: ChromeWebStorePublishOptions): Promise<ChromeWebStorePublishResult>;
|
|
6
6
|
export declare interface GoogleServiceAccount {
|
|
7
7
|
client_email: string
|
|
8
8
|
private_key: string
|
|
@@ -39,6 +39,23 @@ export declare interface ChromePublishResult {
|
|
|
39
39
|
state: string
|
|
40
40
|
warningInfo?: { warnings?: Array<{ reason: string, description: string }> }
|
|
41
41
|
}
|
|
42
|
+
export declare interface ChromeDeferredPublishResult {
|
|
43
|
+
state: string
|
|
44
|
+
submittedVersion?: string
|
|
45
|
+
reason: string
|
|
46
|
+
}
|
|
47
|
+
export declare interface ChromePublishedVersionResult {
|
|
48
|
+
state: string
|
|
49
|
+
version: string
|
|
50
|
+
reason: string
|
|
51
|
+
}
|
|
52
|
+
export declare interface ChromeWebStorePublishResult {
|
|
53
|
+
packagePath: string
|
|
54
|
+
upload?: ChromeUploadResult
|
|
55
|
+
publish?: ChromePublishResult
|
|
56
|
+
deferred?: ChromeDeferredPublishResult
|
|
57
|
+
alreadyPublished?: ChromePublishedVersionResult
|
|
58
|
+
}
|
|
42
59
|
export declare interface ChromeWebStorePublishOptions extends ChromeWebStoreClientOptions {
|
|
43
60
|
version: string
|
|
44
61
|
cwd?: string
|
package/dist/chrome-web-store.js
CHANGED
|
@@ -121,10 +121,38 @@ export class ChromeWebStoreClient {
|
|
|
121
121
|
throw Error("[browser-extension] Chrome Web Store package processing timed out");
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
+
function pendingReview(status) {
|
|
125
|
+
if (status.submittedItemRevisionStatus?.state !== "PENDING_REVIEW")
|
|
126
|
+
return;
|
|
127
|
+
const submittedVersion = status.submittedItemRevisionStatus.distributionChannels?.[0]?.crxVersion;
|
|
128
|
+
return {
|
|
129
|
+
state: status.submittedItemRevisionStatus.state,
|
|
130
|
+
submittedVersion,
|
|
131
|
+
reason: submittedVersion ? `Chrome Web Store version ${submittedVersion} is already pending review` : "A Chrome Web Store revision is already pending review"
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function publishedVersion(status, version) {
|
|
135
|
+
const published = status.publishedItemRevisionStatus;
|
|
136
|
+
if (!published || !["PUBLISHED", "PUBLISHED_TO_TESTERS"].includes(published.state))
|
|
137
|
+
return;
|
|
138
|
+
if (!published.distributionChannels?.some((channel) => channel.crxVersion === version))
|
|
139
|
+
return;
|
|
140
|
+
return {
|
|
141
|
+
state: published.state,
|
|
142
|
+
version,
|
|
143
|
+
reason: `Chrome Web Store version ${version} is already ${published.state.toLowerCase().replaceAll("_", " ")}`
|
|
144
|
+
};
|
|
145
|
+
}
|
|
124
146
|
export async function publishChromeExtension(config, options) {
|
|
125
147
|
if (!config.chromeWebStore)
|
|
126
148
|
throw Error("[browser-extension] Chrome publishing needs chromeWebStore.publisherId and chromeWebStore.itemId in config/extension.ts");
|
|
127
|
-
const cwd = options.cwd ?? process.cwd(), packagePath = options.packagePath ?? await packageExtension(config, { target: "chrome", version: options.version, cwd }), client = new ChromeWebStoreClient(options),
|
|
149
|
+
const cwd = options.cwd ?? process.cwd(), packagePath = options.packagePath ?? await packageExtension(config, { target: "chrome", version: options.version, cwd }), client = new ChromeWebStoreClient(options), status = await client.fetchStatus(config.chromeWebStore), alreadyPublished = publishedVersion(status, options.version);
|
|
150
|
+
if (alreadyPublished)
|
|
151
|
+
return { packagePath, alreadyPublished };
|
|
152
|
+
const deferred = pendingReview(status);
|
|
153
|
+
if (deferred)
|
|
154
|
+
return { packagePath, deferred };
|
|
155
|
+
const upload = await client.upload(config.chromeWebStore, packagePath);
|
|
128
156
|
if (upload.uploadState === "IN_PROGRESS")
|
|
129
157
|
await client.waitForUpload(config.chromeWebStore);
|
|
130
158
|
else if (upload.uploadState !== "SUCCEEDED")
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/safari.d.ts
CHANGED
|
@@ -120,6 +120,8 @@ export declare interface SafariPublishResult {
|
|
|
120
120
|
exportPath: string
|
|
121
121
|
buildNumber: string
|
|
122
122
|
artifacts: SafariPublishedArtifact[]
|
|
123
|
+
deferred: Array<{ platform: SafariPlatform, version: string, state?: string, reason: string }>
|
|
124
|
+
alreadyPublished: Array<{ platform: SafariPlatform, version: string, state?: string }>
|
|
123
125
|
attachments: Array<{ platform: SafariPlatform, versionId: string, buildId: string, buildNumber: string }>
|
|
124
126
|
appStoreSubmission?: {
|
|
125
127
|
versions: Array<{ platform: SafariPlatform, versionId: string, localizationId: string }>
|
package/dist/safari.js
CHANGED
|
@@ -329,20 +329,36 @@ export async function publishSafariApp(config, options) {
|
|
|
329
329
|
throw Error("[browser-extension] Safari publishing needs at least one platform");
|
|
330
330
|
const { AppStoreConnectClient, attachSafariBuilds, provisionSafariApp } = await import("./app-store-connect"), provisioned = await provisionSafariApp(config, {
|
|
331
331
|
...auth,
|
|
332
|
-
version: options.version,
|
|
332
|
+
version: options.validateOnly ? void 0 : options.version,
|
|
333
333
|
platforms
|
|
334
334
|
});
|
|
335
335
|
if (!provisioned.appRecord.exists)
|
|
336
336
|
throw Error("[browser-extension] the App Store Connect app record is missing; create it once in App Store Connect before publishing");
|
|
337
|
+
const publishablePlatforms = options.validateOnly ? platforms : platforms.filter((platform) => provisioned.appStoreVersions.some((version) => version.platform === platform && version.status !== "deferred" && version.status !== "published")), deferred = provisioned.appStoreVersions.filter((version) => version.status === "deferred").map((version) => ({
|
|
338
|
+
platform: version.platform,
|
|
339
|
+
version: version.version,
|
|
340
|
+
state: version.appStoreState,
|
|
341
|
+
reason: version.reason ?? `Safari ${version.platform} publication is deferred`
|
|
342
|
+
})), alreadyPublished = provisioned.appStoreVersions.filter((version) => version.status === "published").map((version) => ({ platform: version.platform, version: version.version, state: version.appStoreState }));
|
|
343
|
+
if (!publishablePlatforms.length)
|
|
344
|
+
return {
|
|
345
|
+
archivePath: "",
|
|
346
|
+
exportPath: "",
|
|
347
|
+
buildNumber,
|
|
348
|
+
artifacts: [],
|
|
349
|
+
attachments: [],
|
|
350
|
+
deferred,
|
|
351
|
+
alreadyPublished
|
|
352
|
+
};
|
|
337
353
|
if (options.build !== !1)
|
|
338
354
|
await buildExtension(config, { target: "safari", version: options.version, cwd });
|
|
339
|
-
const appName = safariAppName(config), dir = safariProjectDir(cwd, options.dir), buildDir = join(dir, "build"), universal =
|
|
355
|
+
const appName = safariAppName(config), dir = safariProjectDir(cwd, options.dir), buildDir = join(dir, "build"), universal = publishablePlatforms.includes("ios");
|
|
340
356
|
let project, projectCwd;
|
|
341
357
|
if (universal) {
|
|
342
358
|
const generated = await createSafariUniversalProject(config, {
|
|
343
359
|
...options,
|
|
344
360
|
build: !1,
|
|
345
|
-
platforms
|
|
361
|
+
platforms: publishablePlatforms
|
|
346
362
|
});
|
|
347
363
|
project = generated.project;
|
|
348
364
|
projectCwd = generated.dir;
|
|
@@ -354,7 +370,7 @@ export async function publishSafariApp(config, options) {
|
|
|
354
370
|
const authArgs = xcodeAuthArgs(auth);
|
|
355
371
|
await mkdir(buildDir, { recursive: !0 });
|
|
356
372
|
const method = options.validateOnly ? "validation" : "app-store-connect", artifacts = [];
|
|
357
|
-
for (const platform of
|
|
373
|
+
for (const platform of publishablePlatforms) {
|
|
358
374
|
const suffix = universal ? `-${platform}` : "", archivePath = join(buildDir, `${appName}${suffix}.xcarchive`), exportPath = join(buildDir, `${options.validateOnly ? "validation" : "upload"}${suffix}`), plistPath = join(buildDir, `ExportOptions.${method}${suffix}.plist`), scheme = universal ? `${appName} (${platform === "ios" ? "iOS" : "macOS"})` : appName, destination = platform === "ios" ? "generic/platform=iOS" : "generic/platform=macOS";
|
|
359
375
|
await rm(archivePath, { recursive: !0, force: !0 });
|
|
360
376
|
await rm(exportPath, { recursive: !0, force: !0 });
|
|
@@ -391,7 +407,7 @@ export async function publishSafariApp(config, options) {
|
|
|
391
407
|
], projectCwd, `Safari ${platform} export`);
|
|
392
408
|
artifacts.push({ platform, archivePath, exportPath });
|
|
393
409
|
}
|
|
394
|
-
const attachments = options.validateOnly ? [] : await attachSafariBuilds(new AppStoreConnectClient(auth), provisioned.appRecord.id, provisioned.appStoreVersions, buildNumber, {
|
|
410
|
+
const attachments = options.validateOnly ? [] : await attachSafariBuilds(new AppStoreConnectClient(auth), provisioned.appRecord.id, provisioned.appStoreVersions.filter((version) => version.status !== "deferred" && version.status !== "published"), buildNumber, {
|
|
395
411
|
timeoutMs: options.processingTimeoutMs,
|
|
396
412
|
pollIntervalMs: options.processingPollIntervalMs
|
|
397
413
|
}), appStoreSubmission = !options.validateOnly && config.safariAppStore ? await (await import("./app-store-submission")).prepareSafariAppStoreSubmission(new AppStoreConnectClient(auth), config, provisioned.appRecord.id, attachments.map((attachment) => ({
|
|
@@ -404,6 +420,8 @@ export async function publishSafariApp(config, options) {
|
|
|
404
420
|
exportPath: firstArtifact.exportPath,
|
|
405
421
|
buildNumber,
|
|
406
422
|
artifacts,
|
|
423
|
+
deferred,
|
|
424
|
+
alreadyPublished,
|
|
407
425
|
attachments,
|
|
408
426
|
appStoreSubmission: appStoreSubmission ? { versions: appStoreSubmission.versions, reviewSubmissionIds: appStoreSubmission.reviewSubmissionIds } : void 0
|
|
409
427
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { scaffoldSafariApp } from './safari';
|
|
2
|
+
import type { ExtensionConfig, ExtensionTarget, SafariPlatform } from './types';
|
|
3
|
+
export declare function resolveExtensionScaffoldTargets(target?: ExtensionScaffoldTarget): ExtensionTarget[];
|
|
4
|
+
/** Scaffold a complete cross-browser extension, including Safari's container app. */
|
|
5
|
+
export declare function scaffoldExtensionProject(options?: ExtensionProjectScaffoldOptions): Promise<ExtensionProjectScaffoldResult>;
|
|
6
|
+
export declare interface ExtensionProjectScaffoldOptions {
|
|
7
|
+
cwd?: string
|
|
8
|
+
name?: string
|
|
9
|
+
target?: ExtensionScaffoldTarget
|
|
10
|
+
bundleId?: string
|
|
11
|
+
teamId?: string
|
|
12
|
+
platforms?: SafariPlatform[]
|
|
13
|
+
version?: string
|
|
14
|
+
force?: boolean
|
|
15
|
+
}
|
|
16
|
+
export declare interface ExtensionProjectScaffoldResult {
|
|
17
|
+
config: ExtensionConfig
|
|
18
|
+
written: string[]
|
|
19
|
+
skipped: string[]
|
|
20
|
+
safari?: Awaited<ReturnType<typeof scaffoldSafariApp>>
|
|
21
|
+
}
|
|
22
|
+
export type ExtensionScaffoldTarget = ExtensionTarget | 'all';
|
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { scaffoldSafariApp } from "./safari";
|
|
6
|
+
export function resolveExtensionScaffoldTargets(target = "all") {
|
|
7
|
+
return target === "all" ? ["chrome", "firefox", "safari"] : [target];
|
|
8
|
+
}
|
|
9
|
+
function safariAppName(name) {
|
|
10
|
+
return name.replace(/[^A-Za-z0-9]/g, "") || "MyExtension";
|
|
11
|
+
}
|
|
12
|
+
function quotedList(values) {
|
|
13
|
+
return `[${values.map((value) => `'${value}'`).join(", ")}]`;
|
|
14
|
+
}
|
|
15
|
+
function extensionConfigSource(config) {
|
|
16
|
+
const safari = config.targets?.includes("safari") ? `
|
|
17
|
+
safariBundleId: '${config.safariBundleId}',
|
|
18
|
+
safariPlatforms: ${quotedList(config.safariPlatforms ?? ["macos", "ios"])},
|
|
19
|
+
safariAppCategory: 'public.app-category.utilities',${config.safariTeamId ? `
|
|
20
|
+
safariTeamId: '${config.safariTeamId}',` : ""}` : "", firefox = config.targets?.includes("firefox") ? `
|
|
21
|
+
// Replace this before publishing to Mozilla Add-ons.
|
|
22
|
+
geckoId: 'extension@example.com',` : "";
|
|
23
|
+
return `import { defineExtension } from '@stacksjs/browser-extension'
|
|
24
|
+
|
|
25
|
+
export default defineExtension({
|
|
26
|
+
name: ${JSON.stringify(config.name)},
|
|
27
|
+
description: 'A browser extension built with Stacks.',
|
|
28
|
+
targets: ${quotedList(config.targets ?? [])},${firefox}${safari}
|
|
29
|
+
background: 'src/background/index.ts',
|
|
30
|
+
content: [
|
|
31
|
+
{ entry: 'src/content/index.ts', matches: ['<all_urls>'], runAt: 'document_start' },
|
|
32
|
+
],
|
|
33
|
+
pages: {
|
|
34
|
+
popup: { template: 'resources/views/popup.stx', script: 'resources/scripts/popup.ts' },
|
|
35
|
+
},
|
|
36
|
+
public: 'public',
|
|
37
|
+
manifest: {
|
|
38
|
+
permissions: ['storage', 'tabs'],
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
`;
|
|
42
|
+
}
|
|
43
|
+
export async function scaffoldExtensionProject(options = {}) {
|
|
44
|
+
const cwd = options.cwd ?? process.cwd(), name = options.name ?? "My Extension", targets = resolveExtensionScaffoldTargets(options.target), appName = safariAppName(name), config = {
|
|
45
|
+
name,
|
|
46
|
+
description: "A browser extension built with Stacks.",
|
|
47
|
+
targets,
|
|
48
|
+
background: "src/background/index.ts",
|
|
49
|
+
content: [{ entry: "src/content/index.ts", matches: ["<all_urls>"], runAt: "document_start" }],
|
|
50
|
+
pages: { popup: { template: "resources/views/popup.stx", script: "resources/scripts/popup.ts" } },
|
|
51
|
+
public: "public",
|
|
52
|
+
manifest: { permissions: ["storage", "tabs"] },
|
|
53
|
+
...targets.includes("firefox") && { geckoId: "extension@example.com" },
|
|
54
|
+
...targets.includes("safari") && {
|
|
55
|
+
safariBundleId: options.bundleId ?? `com.example.${appName}`,
|
|
56
|
+
safariTeamId: options.teamId,
|
|
57
|
+
safariPlatforms: options.platforms ?? ["macos", "ios"],
|
|
58
|
+
safariAppCategory: "public.app-category.utilities"
|
|
59
|
+
}
|
|
60
|
+
}, written = [], skipped = [], write = async (relative, content) => {
|
|
61
|
+
const absolute = join(cwd, relative);
|
|
62
|
+
if (existsSync(absolute) && !options.force) {
|
|
63
|
+
skipped.push(relative);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
await mkdir(dirname(absolute), { recursive: !0 });
|
|
67
|
+
await Bun.write(absolute, content);
|
|
68
|
+
written.push(relative);
|
|
69
|
+
};
|
|
70
|
+
await write("config/extension.ts", extensionConfigSource(config));
|
|
71
|
+
await write("src/background/index.ts", `console.log(${JSON.stringify(`[${name}] background ready`)})
|
|
72
|
+
`);
|
|
73
|
+
await write("src/content/index.ts", `console.log(${JSON.stringify(`[${name}] content script loaded`)})
|
|
74
|
+
`);
|
|
75
|
+
await write("resources/scripts/popup.ts", `console.log(${JSON.stringify(`[${name}] popup ready`)})
|
|
76
|
+
`);
|
|
77
|
+
await write("resources/views/popup.stx", `<main class="popup">
|
|
78
|
+
<h1>${name}</h1>
|
|
79
|
+
<p>Edit resources/views/popup.stx to build your popup.</p>
|
|
80
|
+
<script src="/popup.js"></script>
|
|
81
|
+
</main>
|
|
82
|
+
`);
|
|
83
|
+
await mkdir(join(cwd, "public"), { recursive: !0 });
|
|
84
|
+
const safari = targets.includes("safari") ? await scaffoldSafariApp(config, {
|
|
85
|
+
cwd,
|
|
86
|
+
bundleId: config.safariBundleId,
|
|
87
|
+
teamId: config.safariTeamId,
|
|
88
|
+
version: options.version,
|
|
89
|
+
force: options.force
|
|
90
|
+
}) : void 0;
|
|
91
|
+
return { config, written, skipped, safari };
|
|
92
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/browser-extension",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.70.
|
|
4
|
+
"version": "0.70.149",
|
|
5
5
|
"description": "Build MV3 browser extensions (Chrome, Firefox, Safari) the Stacks way — manifest, content/background scripts, DNR rules, packaging, Safari container app, all config-driven.",
|
|
6
6
|
"author": "Chris Breuer",
|
|
7
7
|
"contributors": [
|