miaoda-expo-devkit 0.1.1-beta.19 → 0.1.1-beta.20

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.
@@ -42,8 +42,10 @@ function presetExpoDevkit(api, options = {}) {
42
42
  "nativewind/babel"
43
43
  ],
44
44
  plugins: [
45
- // lucide tree-shaking:所有环境都需要,Metro 不具备 tree-shaking 能力
46
- ...lucide !== false ? [[require.resolve("./plugin-lucide-react-native"), lucide]] : [],
45
+ // lucide tree-shaking:暂时禁用
46
+ // ...(lucide !== false
47
+ // ? [[require.resolve('./plugin-lucide-react-native'), lucide]]
48
+ // : []),
47
49
  // jsx-source 仅开发环境注入,生产无需调试元数据
48
50
  ...isDev ? [[require.resolve("./plugin-jsx-source"), { rootDir, excludePaths }]] : []
49
51
  ]
package/dist/metro.d.mts CHANGED
@@ -147,6 +147,14 @@ declare function withRouteEndpoint(config: MetroConfig, options: RouteEndpointOp
147
147
  * module.exports = withDevkit(getDefaultConfig(__dirname));
148
148
  */
149
149
 
150
+ /**
151
+ * Android 平台:将 expo-notifications 替换为 stub。
152
+ * stub 内部根据 isRunningInExpoGo() 决定是 no-op(Expo Go)还是透传真实模块(Development Build)。
153
+ *
154
+ * 注意:此 wrapper 必须在 if (__DEV__) 外部调用,因为它需要在所有构建模式下生效。
155
+ * Expo Go 中 native module 的缺失是运行时问题,与开发/生产模式无关。
156
+ */
157
+ declare function withExpoNotificationsStub(config: MetroConfig): MetroConfig;
150
158
  /** withDevkit 的配置选项 */
151
159
  interface DevkitOptions {
152
160
  /**
@@ -266,4 +274,4 @@ declare function withCssInterop(config: MetroConfig): MetroConfig;
266
274
  */
267
275
  declare function withEsbuildMinify(config: MetroConfig): MetroConfig;
268
276
 
269
- export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
277
+ export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withExpoNotificationsStub, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
package/dist/metro.d.ts CHANGED
@@ -147,6 +147,14 @@ declare function withRouteEndpoint(config: MetroConfig, options: RouteEndpointOp
147
147
  * module.exports = withDevkit(getDefaultConfig(__dirname));
148
148
  */
149
149
 
150
+ /**
151
+ * Android 平台:将 expo-notifications 替换为 stub。
152
+ * stub 内部根据 isRunningInExpoGo() 决定是 no-op(Expo Go)还是透传真实模块(Development Build)。
153
+ *
154
+ * 注意:此 wrapper 必须在 if (__DEV__) 外部调用,因为它需要在所有构建模式下生效。
155
+ * Expo Go 中 native module 的缺失是运行时问题,与开发/生产模式无关。
156
+ */
157
+ declare function withExpoNotificationsStub(config: MetroConfig): MetroConfig;
150
158
  /** withDevkit 的配置选项 */
151
159
  interface DevkitOptions {
152
160
  /**
@@ -266,4 +274,4 @@ declare function withCssInterop(config: MetroConfig): MetroConfig;
266
274
  */
267
275
  declare function withEsbuildMinify(config: MetroConfig): MetroConfig;
268
276
 
269
- export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
277
+ export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withExpoNotificationsStub, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
package/dist/metro.js CHANGED
@@ -36,6 +36,7 @@ __export(metro_exports, {
36
36
  withDevkit: () => withDevkit,
37
37
  withEntryInjection: () => withEntryInjection,
38
38
  withEsbuildMinify: () => withEsbuildMinify,
39
+ withExpoNotificationsStub: () => withExpoNotificationsStub,
39
40
  withNativeWind: () => withNativeWind,
40
41
  withRouteEndpoint: () => withRouteEndpoint,
41
42
  withWorkspaceNodeModules: () => withWorkspaceNodeModules
@@ -342,6 +343,7 @@ try {
342
343
  withDevkit,
343
344
  withEntryInjection,
344
345
  withEsbuildMinify,
346
+ withExpoNotificationsStub,
345
347
  withNativeWind,
346
348
  withRouteEndpoint,
347
349
  withWorkspaceNodeModules
package/dist/metro.mjs CHANGED
@@ -304,6 +304,7 @@ export {
304
304
  withDevkit,
305
305
  withEntryInjection,
306
306
  withEsbuildMinify,
307
+ withExpoNotificationsStub,
307
308
  withNativeWind,
308
309
  withRouteEndpoint,
309
310
  withWorkspaceNodeModules
@@ -4,29 +4,134 @@ var import_react_native = require("react-native");
4
4
  if (!(0, import_expo.isRunningInExpoGo)()) {
5
5
  module.exports = require("expo-notifications");
6
6
  } else {
7
- let _alertShown = false;
8
- const showAlert = () => {
9
- if (_alertShown) return;
10
- _alertShown = true;
11
- import_react_native.Alert.alert(
12
- "\u79D2\u54D2\u901A\u77E5",
13
- "\u53D7Android\u5E73\u53F0\u9650\u5236, \u626B\u7801\u4F53\u9A8C\u4E0D\u652F\u6301\u672C\u5730\u901A\u77E5\u3002\n\n \u6682\u65F6\u65E0\u6CD5\u5B8C\u6574\u9A8C\u8BC1\u6B64\u529F\u80FD",
14
- [{ text: "\u77E5\u9053\u4E86" }]
15
- );
7
+ let showDetailedAlert = function(apiName, lines, isValid, errors) {
8
+ const statusLine = isValid ? "\u79D2\u54D2\u901A\u77E5\u60A8 \u6D88\u606F\u63A8\u9001\u9A8C\u8BC1\u901A\u8FC7" : "\u9A8C\u8BC1\u672A\u901A\u8FC7";
9
+ const parts = [statusLine, "", ...lines];
10
+ if (!isValid && errors && errors.length > 0) {
11
+ parts.push("");
12
+ parts.push(`\u95EE\u9898: ${errors.join(" / ")}`);
13
+ parts.push("");
14
+ parts.push("\u8BF7\u524D\u5F80\u79D2\u54D2\u5E73\u53F0\u4FEE\u6539\u901A\u77E5\u914D\u7F6E\u540E\u91CD\u65B0\u9A8C\u8BC1");
15
+ } else {
16
+ parts.push("");
17
+ parts.push("\u901A\u77E5\u914D\u7F6E\u6B63\u786E\uFF0C\u53EF\u4EE5\u653E\u5FC3\u53D1\u5E03");
18
+ }
19
+ import_react_native.Alert.alert(apiName, parts.join("\n"), [{ text: "\u77E5\u9053\u4E86" }]);
20
+ }, formatScheduleRequest = function(request) {
21
+ if (!request || typeof request !== "object") {
22
+ return ["request: (\u65E0\u6548\u503C)"];
23
+ }
24
+ const req = request;
25
+ const content = req["content"] && typeof req["content"] === "object" ? req["content"] : void 0;
26
+ const trigger = req["trigger"];
27
+ const lines = [];
28
+ const titleVal = content?.["title"];
29
+ const bodyVal = content?.["body"];
30
+ lines.push(`\u901A\u77E5\u6807\u9898: ${titleVal != null ? JSON.stringify(String(titleVal)) : "(\u672A\u586B\u5199)"}`);
31
+ lines.push(`\u901A\u77E5\u5185\u5BB9: ${bodyVal != null ? JSON.stringify(String(bodyVal)) : "(\u672A\u586B\u5199)"}`);
32
+ if (content?.["subtitle"] != null) {
33
+ const sub = JSON.stringify(String(content["subtitle"]));
34
+ lines.push(`\u526F\u6807\u9898: ${sub.length > 42 ? sub.slice(0, 42) + "\u2026" : sub}`);
35
+ }
36
+ if (content?.["data"] != null) {
37
+ const dataStr = JSON.stringify(content["data"]);
38
+ lines.push(`\u9644\u52A0\u6570\u636E: ${dataStr.length > 40 ? dataStr.slice(0, 40) + "\u2026" : dataStr}`);
39
+ }
40
+ if (trigger == null) {
41
+ lines.push("\u53D1\u9001\u65F6\u673A: \u7ACB\u5373\u53D1\u9001");
42
+ } else if (typeof trigger === "object") {
43
+ const t = trigger;
44
+ if (t["type"] === "timeInterval") {
45
+ lines.push(`\u53D1\u9001\u65F6\u673A: ${String(t["seconds"])} \u79D2\u540E`);
46
+ } else if (t["type"] === "date") {
47
+ lines.push(`\u53D1\u9001\u65F6\u673A: \u6307\u5B9A\u65F6\u95F4 ${String(t["value"] ?? "(\u672A\u77E5)")}`);
48
+ } else {
49
+ const ts = JSON.stringify(trigger);
50
+ lines.push(`\u53D1\u9001\u65F6\u673A: ${ts.length > 40 ? ts.slice(0, 40) + "\u2026" : ts}`);
51
+ }
52
+ } else {
53
+ lines.push(`\u53D1\u9001\u65F6\u673A: ${String(trigger)}`);
54
+ }
55
+ return lines;
56
+ }, validateScheduleRequest = function(request) {
57
+ const errors = [];
58
+ if (!request || typeof request !== "object") {
59
+ errors.push("request \u4E0D\u80FD\u4E3A\u7A7A");
60
+ return { ok: false, errors };
61
+ }
62
+ const req = request;
63
+ if (!req["content"] || typeof req["content"] !== "object") {
64
+ errors.push("request.content \u4E0D\u80FD\u4E3A\u7A7A");
65
+ return { ok: false, errors };
66
+ }
67
+ const content = req["content"];
68
+ const titleOk = typeof content["title"] === "string" && content["title"].trim().length > 0;
69
+ const bodyOk = typeof content["body"] === "string" && content["body"].trim().length > 0;
70
+ if (!titleOk && !bodyOk) {
71
+ errors.push("content.title \u548C content.body \u5747\u4E3A\u7A7A");
72
+ }
73
+ const trigger = req["trigger"];
74
+ if (trigger != null && typeof trigger === "object") {
75
+ const t = trigger;
76
+ if (t["type"] === "timeInterval") {
77
+ if (typeof t["seconds"] !== "number" || t["seconds"] <= 0) {
78
+ errors.push("trigger.seconds \u5FC5\u987B > 0");
79
+ }
80
+ }
81
+ }
82
+ return { ok: errors.length === 0, errors };
83
+ }, validateChannel = function(channelId, channel) {
84
+ const errors = [];
85
+ if (typeof channelId !== "string" || channelId.trim().length === 0) {
86
+ errors.push("channelId \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
87
+ }
88
+ if (!channel || typeof channel !== "object") {
89
+ errors.push("channel \u4E0D\u80FD\u4E3A\u7A7A");
90
+ return { ok: false, errors };
91
+ }
92
+ const ch = channel;
93
+ if (typeof ch["name"] !== "string" || ch["name"].trim().length === 0) {
94
+ errors.push("channel.name \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
95
+ }
96
+ return { ok: errors.length === 0, errors };
97
+ };
98
+ var showDetailedAlert2 = showDetailedAlert, formatScheduleRequest2 = formatScheduleRequest, validateScheduleRequest2 = validateScheduleRequest, validateChannel2 = validateChannel;
99
+ const DENIED_PERMISSION = {
100
+ status: "denied",
101
+ granted: false,
102
+ canAskAgain: false,
103
+ expires: "never"
16
104
  };
17
- const DENIED_PERMISSION = { status: "denied", granted: false, canAskAgain: false, expires: "never" };
18
- const noopPermission = async () => {
19
- showAlert();
105
+ const handleRequestPermissionsAsync = async () => {
106
+ showDetailedAlert(
107
+ "\u8BF7\u6C42\u901A\u77E5\u6743\u9650",
108
+ ["\u626B\u7801\u9884\u89C8\u73AF\u5883\u6A21\u62DF\u8FD4\u56DE\u672A\u6388\u6743", "\u53D1\u5E03\u540E\u4F1A\u5411\u7528\u6237\u5F39\u51FA\u7CFB\u7EDF\u6388\u6743\u5F39\u7A97"],
109
+ true
110
+ );
20
111
  return DENIED_PERMISSION;
21
112
  };
22
- const noopListener = () => {
23
- showAlert();
24
- return { remove: () => {
25
- } };
113
+ const handleSetNotificationChannelAsync = async (channelId, channel) => {
114
+ const { ok, errors } = validateChannel(channelId, channel);
115
+ const ch = channel && typeof channel === "object" ? channel : {};
116
+ const chStr = JSON.stringify(channel);
117
+ const lines = [
118
+ `\u6E20\u9053 ID: ${JSON.stringify(channelId)}`,
119
+ `\u6E20\u9053\u540D\u79F0: ${JSON.stringify(ch["name"] ?? "(\u672A\u8BBE\u7F6E)")}`,
120
+ `\u5B8C\u6574\u914D\u7F6E: ${chStr.length > 60 ? chStr.slice(0, 60) + "\u2026" : chStr}`
121
+ ];
122
+ showDetailedAlert("\u521B\u5EFA\u901A\u77E5\u6E20\u9053", lines, ok, ok ? void 0 : errors);
123
+ return null;
26
124
  };
27
- const noop = async () => {
28
- showAlert();
125
+ const handleScheduleNotificationAsync = async (request) => {
126
+ const { ok, errors } = validateScheduleRequest(request);
127
+ const lines = formatScheduleRequest(request);
128
+ showDetailedAlert("\u53D1\u9001\u672C\u5730\u901A\u77E5", lines, ok, ok ? void 0 : errors);
129
+ return void 0;
29
130
  };
131
+ const noopPermission = async () => DENIED_PERMISSION;
132
+ const noopListener = () => ({ remove: () => {
133
+ } });
134
+ const noop = async () => void 0;
30
135
  const enums = {
31
136
  AndroidNotificationPriority: {
32
137
  MIN: "min",
@@ -45,9 +150,15 @@ if (!(0, import_expo.isRunningInExpoGo)()) {
45
150
  YEARLY: "yearly"
46
151
  }
47
152
  };
153
+ const coreHandlers = {
154
+ requestPermissionsAsync: handleRequestPermissionsAsync,
155
+ setNotificationChannelAsync: handleSetNotificationChannelAsync,
156
+ scheduleNotificationAsync: handleScheduleNotificationAsync
157
+ };
48
158
  module.exports = new Proxy(enums, {
49
159
  get(target, key) {
50
160
  if (key in target) return target[key];
161
+ if (key in coreHandlers) return coreHandlers[key];
51
162
  if (key.endsWith("PermissionsAsync")) return noopPermission;
52
163
  if (key.endsWith("Listener")) return noopListener;
53
164
  return noop;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miaoda-expo-devkit",
3
- "version": "0.1.1-beta.19",
3
+ "version": "0.1.1-beta.20",
4
4
  "description": "Expo 应用开发工具集:Sentry DSN 替换 stub、错误/网络捕获、Metro 符号化",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",