@stacksjs/browser-extension 0.70.113 → 0.70.115
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 +45 -5
- package/dist/build.d.ts +2 -0
- package/dist/build.js +14 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -0
- package/dist/manifest.d.ts +8 -1
- package/dist/manifest.js +9 -3
- package/dist/package.js +1 -1
- package/dist/safari.d.ts +79 -0
- package/dist/safari.js +199 -0
- package/dist/types.d.ts +5 -1
- package/package.json +6 -4
- package/safari-template/README.md +63 -0
- package/safari-template/__APP_NAME__/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
- package/safari-template/__APP_NAME__/Assets.xcassets/Contents.json +6 -0
- package/safari-template/__APP_NAME__/Assets.xcassets/ExtensionIcon.imageset/Contents.json +22 -0
- package/safari-template/__APP_NAME__/ContentView.swift +74 -0
- package/safari-template/__APP_NAME__/Info.plist +32 -0
- package/safari-template/__APP_NAME__/__APP_NAME__.entitlements +8 -0
- package/safari-template/__APP_NAME__/__APP_NAME__App.swift +15 -0
- package/safari-template/__APP_NAME__ Extension/Info.plist +31 -0
- package/safari-template/__APP_NAME__ Extension/Resources/.gitkeep +1 -0
- package/safari-template/__APP_NAME__ Extension/SafariWebExtensionHandler.swift +32 -0
- package/safari-template/__APP_NAME__ Extension/__APP_NAME___Extension.entitlements +8 -0
- package/safari-template/__APP_NAME__.xcodeproj/project.pbxproj +490 -0
- package/safari-template/__APP_NAME__.xcodeproj/xcshareddata/xcschemes/__APP_NAME__.xcscheme +102 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"images" : [
|
|
3
|
+
{
|
|
4
|
+
"filename" : "icon-16.png",
|
|
5
|
+
"idiom" : "mac",
|
|
6
|
+
"scale" : "1x",
|
|
7
|
+
"size" : "16x16"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"filename" : "icon-32.png",
|
|
11
|
+
"idiom" : "mac",
|
|
12
|
+
"scale" : "2x",
|
|
13
|
+
"size" : "16x16"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"filename" : "icon-32.png",
|
|
17
|
+
"idiom" : "mac",
|
|
18
|
+
"scale" : "1x",
|
|
19
|
+
"size" : "32x32"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"filename" : "icon-64.png",
|
|
23
|
+
"idiom" : "mac",
|
|
24
|
+
"scale" : "2x",
|
|
25
|
+
"size" : "32x32"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"filename" : "icon-128.png",
|
|
29
|
+
"idiom" : "mac",
|
|
30
|
+
"scale" : "1x",
|
|
31
|
+
"size" : "128x128"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"filename" : "icon-256.png",
|
|
35
|
+
"idiom" : "mac",
|
|
36
|
+
"scale" : "2x",
|
|
37
|
+
"size" : "128x128"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"filename" : "icon-256.png",
|
|
41
|
+
"idiom" : "mac",
|
|
42
|
+
"scale" : "1x",
|
|
43
|
+
"size" : "256x256"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"filename" : "icon-512.png",
|
|
47
|
+
"idiom" : "mac",
|
|
48
|
+
"scale" : "2x",
|
|
49
|
+
"size" : "256x256"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"filename" : "icon-512.png",
|
|
53
|
+
"idiom" : "mac",
|
|
54
|
+
"scale" : "1x",
|
|
55
|
+
"size" : "512x512"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"filename" : "icon-1024.png",
|
|
59
|
+
"idiom" : "mac",
|
|
60
|
+
"scale" : "2x",
|
|
61
|
+
"size" : "512x512"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"info" : {
|
|
65
|
+
"author" : "xcode",
|
|
66
|
+
"version" : 1
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"images" : [
|
|
3
|
+
{
|
|
4
|
+
"filename" : "extension-icon-128.png",
|
|
5
|
+
"idiom" : "universal",
|
|
6
|
+
"scale" : "1x"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"filename" : "extension-icon-256.png",
|
|
10
|
+
"idiom" : "universal",
|
|
11
|
+
"scale" : "2x"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"idiom" : "universal",
|
|
15
|
+
"scale" : "3x"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"info" : {
|
|
19
|
+
"author" : "xcode",
|
|
20
|
+
"version" : 1
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import SafariServices
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
/// The bundle identifier of the embedded Safari Web Extension target.
|
|
5
|
+
/// Keep in sync with the extension target's PRODUCT_BUNDLE_IDENTIFIER.
|
|
6
|
+
let extensionBundleIdentifier = "__EXT_BUNDLE_ID__"
|
|
7
|
+
|
|
8
|
+
struct ContentView: View {
|
|
9
|
+
@State private var extensionEnabled: Bool?
|
|
10
|
+
|
|
11
|
+
var body: some View {
|
|
12
|
+
VStack(spacing: 16) {
|
|
13
|
+
Image("ExtensionIcon")
|
|
14
|
+
.resizable()
|
|
15
|
+
.interpolation(.high)
|
|
16
|
+
.frame(width: 96, height: 96)
|
|
17
|
+
.shadow(radius: 4, y: 2)
|
|
18
|
+
|
|
19
|
+
Text("__APP_DISPLAY_NAME__")
|
|
20
|
+
.font(.largeTitle)
|
|
21
|
+
.fontWeight(.bold)
|
|
22
|
+
|
|
23
|
+
Text(statusText)
|
|
24
|
+
.font(.body)
|
|
25
|
+
.foregroundStyle(.secondary)
|
|
26
|
+
.multilineTextAlignment(.center)
|
|
27
|
+
.fixedSize(horizontal: false, vertical: true)
|
|
28
|
+
|
|
29
|
+
Button("Open Safari Extension Settings…") {
|
|
30
|
+
SFSafariApplication.showPreferencesForExtension(withIdentifier: extensionBundleIdentifier) { error in
|
|
31
|
+
if let error {
|
|
32
|
+
NSLog("Failed to open Safari extension settings: \(error.localizedDescription)")
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
.controlSize(.large)
|
|
37
|
+
|
|
38
|
+
Button("Quit") {
|
|
39
|
+
NSApplication.shared.terminate(nil)
|
|
40
|
+
}
|
|
41
|
+
.keyboardShortcut("q")
|
|
42
|
+
}
|
|
43
|
+
.padding(32)
|
|
44
|
+
.frame(width: 440, height: 360)
|
|
45
|
+
.onAppear(perform: refreshExtensionState)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private var statusText: String {
|
|
49
|
+
switch extensionEnabled {
|
|
50
|
+
case .some(true):
|
|
51
|
+
return "The extension is enabled in Safari. You're protected."
|
|
52
|
+
case .some(false):
|
|
53
|
+
return "The extension is installed but turned off. Enable it in Safari → Settings → Extensions."
|
|
54
|
+
case .none:
|
|
55
|
+
return "This app contains the __APP_DISPLAY_NAME__ Safari extension. Enable it in Safari → Settings → Extensions."
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private func refreshExtensionState() {
|
|
60
|
+
SFSafariExtensionManager.getStateOfSafariExtension(withIdentifier: extensionBundleIdentifier) { state, error in
|
|
61
|
+
if let error {
|
|
62
|
+
NSLog("Failed to read Safari extension state: \(error.localizedDescription)")
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
DispatchQueue.main.async {
|
|
66
|
+
extensionEnabled = state?.isEnabled ?? false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#Preview {
|
|
73
|
+
ContentView()
|
|
74
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
7
|
+
<key>CFBundleDisplayName</key>
|
|
8
|
+
<string>__APP_DISPLAY_NAME__</string>
|
|
9
|
+
<key>CFBundleExecutable</key>
|
|
10
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
11
|
+
<key>CFBundleIdentifier</key>
|
|
12
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
13
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
14
|
+
<string>6.0</string>
|
|
15
|
+
<key>CFBundleName</key>
|
|
16
|
+
<string>$(PRODUCT_NAME)</string>
|
|
17
|
+
<key>CFBundlePackageType</key>
|
|
18
|
+
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
|
19
|
+
<key>CFBundleShortVersionString</key>
|
|
20
|
+
<string>$(MARKETING_VERSION)</string>
|
|
21
|
+
<key>CFBundleVersion</key>
|
|
22
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
23
|
+
<key>LSApplicationCategoryType</key>
|
|
24
|
+
<string>public.app-category.utilities</string>
|
|
25
|
+
<key>LSMinimumSystemVersion</key>
|
|
26
|
+
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
|
27
|
+
<key>NSHumanReadableCopyright</key>
|
|
28
|
+
<string>Copyright © __YEAR__
|
|
29
|
+
<key>NSPrincipalClass</key>
|
|
30
|
+
<string>NSApplication</string>
|
|
31
|
+
</dict>
|
|
32
|
+
</plist>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
@main
|
|
4
|
+
struct __APP_NAME__App: App {
|
|
5
|
+
var body: some Scene {
|
|
6
|
+
WindowGroup {
|
|
7
|
+
ContentView()
|
|
8
|
+
}
|
|
9
|
+
.windowResizability(.contentSize)
|
|
10
|
+
.commands {
|
|
11
|
+
// A single-purpose container app has no document lifecycle.
|
|
12
|
+
CommandGroup(replacing: .newItem) {}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
7
|
+
<key>CFBundleDisplayName</key>
|
|
8
|
+
<string>__APP_DISPLAY_NAME__</string>
|
|
9
|
+
<key>CFBundleExecutable</key>
|
|
10
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
11
|
+
<key>CFBundleIdentifier</key>
|
|
12
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
13
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
14
|
+
<string>6.0</string>
|
|
15
|
+
<key>CFBundleName</key>
|
|
16
|
+
<string>$(PRODUCT_NAME)</string>
|
|
17
|
+
<key>CFBundlePackageType</key>
|
|
18
|
+
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
|
19
|
+
<key>CFBundleShortVersionString</key>
|
|
20
|
+
<string>$(MARKETING_VERSION)</string>
|
|
21
|
+
<key>CFBundleVersion</key>
|
|
22
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
23
|
+
<key>NSExtension</key>
|
|
24
|
+
<dict>
|
|
25
|
+
<key>NSExtensionPointIdentifier</key>
|
|
26
|
+
<string>com.apple.Safari.web-extension</string>
|
|
27
|
+
<key>NSExtensionPrincipalClass</key>
|
|
28
|
+
<string>$(PRODUCT_MODULE_NAME).SafariWebExtensionHandler</string>
|
|
29
|
+
</dict>
|
|
30
|
+
</dict>
|
|
31
|
+
</plist>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Placeholder — run `bun run safari:sync` to mirror dist-safari here.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import SafariServices
|
|
2
|
+
import os.log
|
|
3
|
+
|
|
4
|
+
/// Bridge for `browser.runtime.sendNativeMessage`. __APP_DISPLAY_NAME__ keeps all
|
|
5
|
+
/// state in the web extension itself (no telemetry, no native storage), so
|
|
6
|
+
/// this only implements the required protocol and echoes a reply — the web
|
|
7
|
+
/// extension never calls it today.
|
|
8
|
+
class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
|
|
9
|
+
func beginRequest(with context: NSExtensionContext) {
|
|
10
|
+
let request = context.inputItems.first as? NSExtensionItem
|
|
11
|
+
|
|
12
|
+
let message: Any?
|
|
13
|
+
if #available(macOS 15.4, *) {
|
|
14
|
+
message = request?.userInfo?[SFExtensionMessageKey]
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
message = request?.userInfo?["message"]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", String(describing: message))
|
|
21
|
+
|
|
22
|
+
let response = NSExtensionItem()
|
|
23
|
+
if #available(macOS 15.4, *) {
|
|
24
|
+
response.userInfo = [SFExtensionMessageKey: ["Response to": message]]
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
response.userInfo = ["message": ["Response to": message]]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
context.completeRequest(returningItems: [response], completionHandler: nil)
|
|
31
|
+
}
|
|
32
|
+
}
|