@stacksjs/ts-cloud 0.9.2 → 0.9.4

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 (191) hide show
  1. package/dist/aws/index.js +1 -269
  2. package/dist/bin/chunk-00kg80qg.js +1 -0
  3. package/dist/bin/chunk-09nwf2gy.js +34 -0
  4. package/dist/bin/chunk-1k5kszjp.js +111 -0
  5. package/dist/bin/chunk-21e0mavm.js +1 -0
  6. package/dist/bin/chunk-271gk1n2.js +6 -0
  7. package/dist/bin/chunk-2empps47.js +2 -0
  8. package/dist/bin/chunk-38pq971s.js +2 -0
  9. package/dist/bin/chunk-3gykfyq4.js +37 -0
  10. package/dist/bin/chunk-3vqfexc4.js +70 -0
  11. package/dist/bin/chunk-4vrqm9h0.js +2 -0
  12. package/dist/bin/chunk-598yf4bs.js +1 -0
  13. package/dist/bin/chunk-5ectjq0b.js +1 -0
  14. package/dist/bin/chunk-5erkxpt7.js +512 -0
  15. package/dist/bin/chunk-5mrtzemj.js +1 -0
  16. package/dist/bin/chunk-5n9fmabb.js +1 -0
  17. package/dist/bin/chunk-9knpg30y.js +1 -0
  18. package/dist/bin/chunk-9pvsff8g.js +1 -0
  19. package/dist/bin/chunk-ax9mr6wm.js +44 -0
  20. package/dist/bin/chunk-axhnkn5g.js +2 -0
  21. package/dist/bin/chunk-c1vcdgvr.js +1 -0
  22. package/dist/bin/chunk-ctd2vg9w.js +2 -0
  23. package/dist/bin/chunk-dbgffky8.js +1 -0
  24. package/dist/bin/chunk-ddk4rt4j.js +6 -0
  25. package/dist/bin/chunk-dwr30vbv.js +1 -0
  26. package/dist/bin/chunk-e0rkrq70.js +1 -0
  27. package/dist/bin/chunk-e3xrwh9z.js +1 -0
  28. package/dist/bin/chunk-etrb03mt.js +1507 -0
  29. package/dist/bin/chunk-fhc6ntvd.js +2 -0
  30. package/dist/bin/chunk-fpm59y25.js +6 -0
  31. package/dist/bin/chunk-fvbxvq6b.js +1 -0
  32. package/dist/bin/chunk-fy8j3y8p.js +92 -0
  33. package/dist/bin/chunk-fz21b57w.js +1 -0
  34. package/dist/bin/chunk-gavvf0pg.js +141 -0
  35. package/dist/bin/chunk-ggn7ax8p.js +4 -0
  36. package/dist/bin/chunk-gpe2prkm.js +1 -0
  37. package/dist/bin/chunk-h5pa5men.js +2 -0
  38. package/dist/bin/chunk-hm08xdxf.js +2 -0
  39. package/dist/bin/chunk-hzgz13nf.js +1 -0
  40. package/dist/bin/chunk-j703btc5.js +50 -0
  41. package/dist/bin/chunk-k9t9wvms.js +1 -0
  42. package/dist/bin/chunk-m669wtgr.js +1 -0
  43. package/dist/bin/chunk-m7dgskt1.js +1 -0
  44. package/dist/bin/chunk-mh0kdzqp.js +2 -0
  45. package/dist/bin/chunk-mr0atd2s.js +2 -0
  46. package/dist/bin/chunk-mz0wbbsj.js +3 -0
  47. package/dist/bin/chunk-ngcyftm2.js +1 -0
  48. package/dist/bin/chunk-p66ptpmr.js +2 -0
  49. package/dist/bin/chunk-qk9qgepa.js +1 -0
  50. package/dist/bin/chunk-rxcvf10f.js +7364 -0
  51. package/dist/bin/chunk-rytk89az.js +60 -0
  52. package/dist/bin/chunk-tga3hhwk.js +6 -0
  53. package/dist/bin/chunk-tx0tqq2k.js +8 -0
  54. package/dist/bin/chunk-vek8a0w6.js +1 -0
  55. package/dist/bin/chunk-vm3q5gf2.js +3 -0
  56. package/dist/bin/chunk-y7s5r8y6.js +3 -0
  57. package/dist/bin/chunk-yv9sth30.js +1 -0
  58. package/dist/bin/chunk-zmegvjp8.js +581 -0
  59. package/dist/bin/cli.js +417 -10597
  60. package/dist/bin/dashboard-server.js +1 -6998
  61. package/dist/chunk-0ccta6z6.js +6 -0
  62. package/dist/chunk-0k1cs6pp.js +1 -0
  63. package/dist/chunk-1egjn203.js +704 -0
  64. package/dist/chunk-2wx29qga.js +5 -0
  65. package/dist/chunk-5m5rqmv7.js +1 -0
  66. package/dist/chunk-8ea5022g.js +114 -0
  67. package/dist/chunk-8xqn3c0w.js +2 -0
  68. package/dist/chunk-b4esxhmw.js +2 -0
  69. package/dist/chunk-b8e5wzwn.js +44 -0
  70. package/dist/chunk-bggt4n6e.js +2 -0
  71. package/dist/chunk-cwkg37rs.js +37 -0
  72. package/dist/chunk-dskvqt67.js +7355 -0
  73. package/dist/chunk-gahsdmxf.js +1617 -0
  74. package/dist/chunk-gnv3r2jg.js +1 -0
  75. package/dist/chunk-hg3c48cp.js +34 -0
  76. package/dist/chunk-m5azeva3.js +2 -0
  77. package/dist/chunk-r3qf56b3.js +92 -0
  78. package/dist/chunk-sdqa9ghv.js +141 -0
  79. package/dist/chunk-svrvvcm7.js +1 -0
  80. package/dist/chunk-v0p3hpc3.js +60 -0
  81. package/dist/chunk-wdzjbecg.js +50 -0
  82. package/dist/chunk-ww8k3g7j.js +1 -0
  83. package/dist/chunk-xmqfc62w.js +1 -0
  84. package/dist/chunk-xrebj679.js +435 -0
  85. package/dist/chunk-xt3s24vr.js +2 -0
  86. package/dist/chunk-y21zk0pn.js +4 -0
  87. package/dist/deploy/attach-credentials.d.ts +57 -0
  88. package/dist/deploy/index.js +1 -168
  89. package/dist/deploy/site-ports.d.ts +151 -0
  90. package/dist/deploy/site-target.d.ts +24 -1
  91. package/dist/dns/index.js +1 -41
  92. package/dist/drivers/index.js +1 -154
  93. package/dist/index.js +100 -6129
  94. package/dist/protection/index.js +1 -89
  95. package/dist/push/index.js +1 -509
  96. package/dist/spend/index.js +1 -173
  97. package/dist/ui/404.html +16 -548
  98. package/dist/ui/_stx/chunk.5ddb5087.js +90 -0
  99. package/dist/ui/_stx/chunk.9fd39d5b.js +86 -0
  100. package/dist/ui/_stx/chunk.d5301f79.js +119 -0
  101. package/dist/ui/_stx/crosswind.222ed683.css +1 -0
  102. package/dist/ui/_stx/crosswind.616c25f3.css +1 -0
  103. package/dist/ui/_stx/crosswind.80baa894.css +320 -0
  104. package/dist/ui/_stx/crosswind.906ee17c.css +1 -0
  105. package/dist/ui/_stx/crosswind.996ed49e.css +1 -0
  106. package/dist/ui/_stx/crosswind.b7a99a5c.css +1 -0
  107. package/dist/ui/_stx/router.fa5bc4dc.js +4 -0
  108. package/dist/ui/_stx/runtime.c696d17a.js +1 -0
  109. package/dist/ui/_stx/style.448ab192.css +1 -0
  110. package/dist/ui/accept-invitation.html +2 -1133
  111. package/dist/ui/access-denied.html +7 -1130
  112. package/dist/ui/account/automation.html +12 -1134
  113. package/dist/ui/account/security.html +13 -1136
  114. package/dist/ui/applications/compose.html +12 -1134
  115. package/dist/ui/applications/new.html +13 -1137
  116. package/dist/ui/data/backups.html +91 -1136
  117. package/dist/ui/data/services.html +89 -1136
  118. package/dist/ui/data/volumes.html +61 -1136
  119. package/dist/ui/index.html +60 -1136
  120. package/dist/ui/infrastructure/topology.html +128 -1135
  121. package/dist/ui/integrations.html +13 -1138
  122. package/dist/ui/operations/alerts.html +59 -1136
  123. package/dist/ui/operations/configuration.html +13 -1135
  124. package/dist/ui/operations/jobs.html +87 -1136
  125. package/dist/ui/operations/maintenance.html +12 -1134
  126. package/dist/ui/operations/observability.html +93 -1136
  127. package/dist/ui/operations/previews.html +12 -1134
  128. package/dist/ui/operations/queue.html +12 -1134
  129. package/dist/ui/operations/regions.html +12 -1134
  130. package/dist/ui/operations/releases.html +12 -1134
  131. package/dist/ui/operations/spend.html +65 -1136
  132. package/dist/ui/operations/workloads.html +115 -1136
  133. package/dist/ui/robots.txt +2 -0
  134. package/dist/ui/security.html +24 -1136
  135. package/dist/ui/server/actions.html +67 -1138
  136. package/dist/ui/server/activity.html +7 -1130
  137. package/dist/ui/server/capacity.html +12 -1134
  138. package/dist/ui/server/database.html +166 -1135
  139. package/dist/ui/server/deployments.html +60 -1136
  140. package/dist/ui/server/diagnostics.html +7 -1130
  141. package/dist/ui/server/firewall.html +286 -1212
  142. package/dist/ui/server/fleet.html +45 -1136
  143. package/dist/ui/server/logs.html +34 -1135
  144. package/dist/ui/server/metrics.html +124 -1140
  145. package/dist/ui/server/security.html +7 -1130
  146. package/dist/ui/server/services.html +46 -1133
  147. package/dist/ui/server/sites.html +287 -1137
  148. package/dist/ui/server/ssh-keys.html +62 -1135
  149. package/dist/ui/server/team.html +155 -1136
  150. package/dist/ui/server/terminal.html +97 -1183
  151. package/dist/ui/serverless/alarms.html +62 -1135
  152. package/dist/ui/serverless/assets.html +47 -1132
  153. package/dist/ui/serverless/cost.html +7 -1130
  154. package/dist/ui/serverless/data.html +46 -1135
  155. package/dist/ui/serverless/deployments.html +47 -1132
  156. package/dist/ui/serverless/firewall.html +7 -1130
  157. package/dist/ui/serverless/functions.html +50 -1136
  158. package/dist/ui/serverless/logs.html +34 -1135
  159. package/dist/ui/serverless/metrics.html +7 -1130
  160. package/dist/ui/serverless/queues.html +58 -1135
  161. package/dist/ui/serverless/secrets.html +62 -1136
  162. package/dist/ui/serverless/traces.html +12 -1134
  163. package/dist/ui/serverless.html +64 -1137
  164. package/dist/ui-src/pages/server/firewall.stx +14 -14
  165. package/package.json +3 -3
  166. package/dist/chunk-01d86gt1.js +0 -1324
  167. package/dist/chunk-050r7ycy.js +0 -46516
  168. package/dist/chunk-29rse4p1.js +0 -12203
  169. package/dist/chunk-32e7ya18.js +0 -642
  170. package/dist/chunk-4cjrg98a.js +0 -597
  171. package/dist/chunk-50jpda9q.js +0 -371
  172. package/dist/chunk-6a1t7fnq.js +0 -12121
  173. package/dist/chunk-728jvrr0.js +0 -1701
  174. package/dist/chunk-7m60qnc8.js +0 -1762
  175. package/dist/chunk-aa2dkn7b.js +0 -205
  176. package/dist/chunk-d48vtdj4.js +0 -433
  177. package/dist/chunk-f55nkpvb.js +0 -8
  178. package/dist/chunk-fgk8cqew.js +0 -152
  179. package/dist/chunk-he9a874b.js +0 -769
  180. package/dist/chunk-hg7rhrgd.js +0 -7274
  181. package/dist/chunk-k2yyatfw.js +0 -10
  182. package/dist/chunk-k4px0bnv.js +0 -23
  183. package/dist/chunk-nsgqsmrh.js +0 -1779
  184. package/dist/chunk-qr803fye.js +0 -2122
  185. package/dist/chunk-rds0sy87.js +0 -1771
  186. package/dist/chunk-rxgchb08.js +0 -42033
  187. package/dist/chunk-ttz2ra5j.js +0 -12
  188. package/dist/chunk-v0bahtg2.js +0 -4
  189. package/dist/chunk-va2yd85b.js +0 -200
  190. package/dist/chunk-x9s0cqfx.js +0 -13
  191. package/dist/chunk-zqtpg06c.js +0 -1752
@@ -1,89 +1 @@
1
- import {
2
- DEFAULT_ATTACK_MODE_HOURS,
3
- MAX_CONTROL_HOURS,
4
- PROTECTION_SETTING,
5
- ProtectionControlStore,
6
- RATE_LIMIT_KEY_SEPARATOR,
7
- RateLimiter,
8
- applyControlsToDdos,
9
- applyControlsToRateLimits,
10
- defaultRateLimitRules,
11
- describePosture,
12
- globMatches,
13
- mergeControlsIntoConfig,
14
- rateLimitHeaders,
15
- rateLimitKey,
16
- ruleMatches
17
- } from "../chunk-d48vtdj4.js";
18
- import {
19
- escapeSecLang,
20
- globToRegex,
21
- isSafePattern,
22
- renderWafConfig,
23
- renderWafInstallScript,
24
- wafEventTelemetry
25
- } from "../chunk-va2yd85b.js";
26
- import {
27
- DEFAULT_DDOS_THRESHOLDS,
28
- applyMitigationFactor,
29
- isValidCidr,
30
- planMitigation,
31
- renderDdosInstallScript,
32
- renderNftablesRuleset,
33
- renderSysctlFile,
34
- sysctlHardening
35
- } from "../chunk-aa2dkn7b.js";
36
- import {
37
- CHAIN_HEADER,
38
- DEFAULT_RECURSION_LIMITS,
39
- DEPTH_HEADER,
40
- RecursionGuard,
41
- TRACE_HEADER,
42
- functionFingerprint,
43
- inspectInvocation,
44
- parseChain,
45
- propagationHeaders,
46
- recursionBlockedResponse
47
- } from "../chunk-050r7ycy.js";
48
- import"../chunk-v0bahtg2.js";
49
- export {
50
- wafEventTelemetry,
51
- sysctlHardening,
52
- ruleMatches,
53
- renderWafInstallScript,
54
- renderWafConfig,
55
- renderSysctlFile,
56
- renderNftablesRuleset,
57
- renderDdosInstallScript,
58
- recursionBlockedResponse,
59
- rateLimitKey,
60
- rateLimitHeaders,
61
- propagationHeaders,
62
- planMitigation,
63
- parseChain,
64
- mergeControlsIntoConfig,
65
- isValidCidr,
66
- isSafePattern,
67
- inspectInvocation,
68
- globToRegex,
69
- globMatches,
70
- functionFingerprint,
71
- escapeSecLang,
72
- describePosture,
73
- defaultRateLimitRules,
74
- applyMitigationFactor,
75
- applyControlsToRateLimits,
76
- applyControlsToDdos,
77
- TRACE_HEADER,
78
- RecursionGuard,
79
- RateLimiter,
80
- RATE_LIMIT_KEY_SEPARATOR,
81
- ProtectionControlStore,
82
- PROTECTION_SETTING,
83
- MAX_CONTROL_HOURS,
84
- DEPTH_HEADER,
85
- DEFAULT_RECURSION_LIMITS,
86
- DEFAULT_DDOS_THRESHOLDS,
87
- DEFAULT_ATTACK_MODE_HOURS,
88
- CHAIN_HEADER
89
- };
1
+ import{$k as H,Sk as y,Tk as z,Uk as A,Vk as B,Wk as C,Xk as D,Yk as E,Zk as F,_k as G,al as I,bl as J,cl as K,dl as L,el as M}from"../chunk-gnv3r2jg.js";import{fl as s,gl as t,hl as u,il as v,jl as w,kl as x}from"../chunk-cwkg37rs.js";import{ll as k,ml as l,nl as m,ol as n,pl as o,ql as p,rl as q,sl as r}from"../chunk-b8e5wzwn.js";import{Bs as a,Cs as b,Ds as c,Es as d,Fs as e,Gs as f,Hs as g,Is as h,Js as i,Ks as j}from"../chunk-dskvqt67.js";import"../chunk-xt3s24vr.js";export{x as wafEventTelemetry,m as sysctlHardening,A as ruleMatches,w as renderWafInstallScript,v as renderWafConfig,n as renderSysctlFile,o as renderNftablesRuleset,p as renderDdosInstallScript,j as recursionBlockedResponse,B as rateLimitKey,D as rateLimitHeaders,i as propagationHeaders,q as planMitigation,f as parseChain,M as mergeControlsIntoConfig,l as isValidCidr,t as isSafePattern,g as inspectInvocation,u as globToRegex,z as globMatches,d as functionFingerprint,s as escapeSecLang,J as describePosture,E as defaultRateLimitRules,r as applyMitigationFactor,K as applyControlsToRateLimits,L as applyControlsToDdos,c as TRACE_HEADER,h as RecursionGuard,C as RateLimiter,y as RATE_LIMIT_KEY_SEPARATOR,I as ProtectionControlStore,F as PROTECTION_SETTING,G as MAX_CONTROL_HOURS,a as DEPTH_HEADER,e as DEFAULT_RECURSION_LIMITS,k as DEFAULT_DDOS_THRESHOLDS,H as DEFAULT_ATTACK_MODE_HOURS,b as CHAIN_HEADER};
@@ -1,509 +1 @@
1
- import"../chunk-v0bahtg2.js";
2
-
3
- // src/push/apns.ts
4
- import * as http2 from "node:http2";
5
- import { createSign } from "node:crypto";
6
- var APNS_PRODUCTION_HOST = "api.push.apple.com";
7
- var APNS_SANDBOX_HOST = "api.sandbox.push.apple.com";
8
- var TOKEN_EXPIRY_MS = 45 * 60 * 1000;
9
-
10
- class APNsClient {
11
- config;
12
- token = null;
13
- tokenGeneratedAt = 0;
14
- client = null;
15
- host;
16
- constructor(config) {
17
- this.config = config;
18
- this.host = config.production ? APNS_PRODUCTION_HOST : APNS_SANDBOX_HOST;
19
- }
20
- generateToken() {
21
- const now = Math.floor(Date.now() / 1000);
22
- if (this.token && Date.now() - this.tokenGeneratedAt < TOKEN_EXPIRY_MS) {
23
- return this.token;
24
- }
25
- const header = {
26
- alg: "ES256",
27
- kid: this.config.keyId
28
- };
29
- const payload = {
30
- iss: this.config.teamId,
31
- iat: now
32
- };
33
- const encodedHeader = Buffer.from(JSON.stringify(header)).toString("base64url");
34
- const encodedPayload = Buffer.from(JSON.stringify(payload)).toString("base64url");
35
- const signatureInput = `${encodedHeader}.${encodedPayload}`;
36
- const sign = createSign("SHA256");
37
- sign.update(signatureInput);
38
- const signature = sign.sign(this.config.privateKey);
39
- const rawSignature = this.derToRaw(signature);
40
- const encodedSignature = rawSignature.toString("base64url");
41
- this.token = `${signatureInput}.${encodedSignature}`;
42
- this.tokenGeneratedAt = Date.now();
43
- return this.token;
44
- }
45
- derToRaw(derSignature) {
46
- let offset = 2;
47
- if (derSignature[offset] !== 2) {
48
- throw new Error("Invalid DER signature: expected 0x02 for R");
49
- }
50
- offset++;
51
- const rLength = derSignature[offset];
52
- offset++;
53
- let r = derSignature.subarray(offset, offset + rLength);
54
- offset += rLength;
55
- if (derSignature[offset] !== 2) {
56
- throw new Error("Invalid DER signature: expected 0x02 for S");
57
- }
58
- offset++;
59
- const sLength = derSignature[offset];
60
- offset++;
61
- let s = derSignature.subarray(offset, offset + sLength);
62
- if (r[0] === 0 && r.length === 33) {
63
- r = r.subarray(1);
64
- }
65
- if (s[0] === 0 && s.length === 33) {
66
- s = s.subarray(1);
67
- }
68
- const result = Buffer.alloc(64);
69
- r.copy(result, 32 - r.length);
70
- s.copy(result, 64 - s.length);
71
- return result;
72
- }
73
- async getClient() {
74
- if (this.client && !this.client.destroyed) {
75
- return this.client;
76
- }
77
- return new Promise((resolve, reject) => {
78
- this.client = http2.connect(`https://${this.host}`);
79
- this.client.on("error", (err) => {
80
- reject(err);
81
- });
82
- this.client.on("connect", () => {
83
- resolve(this.client);
84
- });
85
- this.client.on("close", () => {
86
- this.client = null;
87
- });
88
- });
89
- }
90
- buildPayload(notification) {
91
- const aps = {};
92
- if (notification.title || notification.body || notification.subtitle) {
93
- aps.alert = {};
94
- if (notification.title)
95
- aps.alert.title = notification.title;
96
- if (notification.subtitle)
97
- aps.alert.subtitle = notification.subtitle;
98
- if (notification.body)
99
- aps.alert.body = notification.body;
100
- }
101
- if (notification.badge !== undefined) {
102
- aps.badge = notification.badge;
103
- }
104
- if (notification.sound !== undefined) {
105
- aps.sound = notification.sound;
106
- }
107
- if (notification.category) {
108
- aps.category = notification.category;
109
- }
110
- if (notification.threadId) {
111
- aps["thread-id"] = notification.threadId;
112
- }
113
- if (notification.contentAvailable) {
114
- aps["content-available"] = 1;
115
- }
116
- if (notification.mutableContent) {
117
- aps["mutable-content"] = 1;
118
- }
119
- if (notification.targetContentId) {
120
- aps["target-content-id"] = notification.targetContentId;
121
- }
122
- const payload = { aps };
123
- if (notification.data) {
124
- Object.assign(payload, notification.data);
125
- }
126
- return payload;
127
- }
128
- async send(notification) {
129
- try {
130
- const client = await this.getClient();
131
- const token = this.generateToken();
132
- const payload = JSON.stringify(this.buildPayload(notification));
133
- const headers = {
134
- ":method": "POST",
135
- ":path": `/3/device/${notification.deviceToken}`,
136
- authorization: `bearer ${token}`,
137
- "apns-topic": this.config.bundleId,
138
- "apns-push-type": notification.pushType || "alert",
139
- "apns-priority": String(notification.priority || 10)
140
- };
141
- if (notification.expiration !== undefined) {
142
- headers["apns-expiration"] = String(notification.expiration);
143
- }
144
- if (notification.collapseId) {
145
- headers["apns-collapse-id"] = notification.collapseId;
146
- }
147
- return new Promise((resolve) => {
148
- const req = client.request(headers);
149
- let responseData = "";
150
- let statusCode = 0;
151
- let apnsId;
152
- req.on("response", (headers2) => {
153
- statusCode = headers2[":status"];
154
- apnsId = headers2["apns-id"];
155
- });
156
- req.on("data", (chunk) => {
157
- responseData += chunk.toString();
158
- });
159
- req.on("end", () => {
160
- if (statusCode === 200) {
161
- resolve({
162
- success: true,
163
- deviceToken: notification.deviceToken,
164
- apnsId,
165
- statusCode
166
- });
167
- } else {
168
- let error = "Unknown error";
169
- let reason;
170
- let timestamp;
171
- if (responseData) {
172
- try {
173
- const parsed = JSON.parse(responseData);
174
- reason = parsed.reason;
175
- timestamp = parsed.timestamp;
176
- error = reason || error;
177
- } catch {
178
- error = responseData;
179
- }
180
- }
181
- resolve({
182
- success: false,
183
- deviceToken: notification.deviceToken,
184
- apnsId,
185
- statusCode,
186
- error,
187
- reason,
188
- timestamp
189
- });
190
- }
191
- });
192
- req.on("error", (err) => {
193
- resolve({
194
- success: false,
195
- deviceToken: notification.deviceToken,
196
- error: err.message
197
- });
198
- });
199
- req.write(payload);
200
- req.end();
201
- });
202
- } catch (error) {
203
- return {
204
- success: false,
205
- deviceToken: notification.deviceToken,
206
- error: error.message
207
- };
208
- }
209
- }
210
- async sendBatch(notifications, options) {
211
- const concurrency = options?.concurrency || 10;
212
- const results = [];
213
- for (let i = 0;i < notifications.length; i += concurrency) {
214
- const batch = notifications.slice(i, i + concurrency);
215
- const batchResults = await Promise.all(batch.map((n) => this.send(n)));
216
- results.push(...batchResults);
217
- }
218
- return {
219
- sent: results.filter((r) => r.success).length,
220
- failed: results.filter((r) => !r.success).length,
221
- results
222
- };
223
- }
224
- async sendSimple(deviceToken, title, body, data) {
225
- return this.send({
226
- deviceToken,
227
- title,
228
- body,
229
- data
230
- });
231
- }
232
- async sendSilent(deviceToken, data) {
233
- return this.send({
234
- deviceToken,
235
- contentAvailable: true,
236
- pushType: "background",
237
- priority: 5,
238
- data
239
- });
240
- }
241
- close() {
242
- if (this.client) {
243
- this.client.close();
244
- this.client = null;
245
- }
246
- this.token = null;
247
- this.tokenGeneratedAt = 0;
248
- }
249
- }
250
- // src/push/fcm.ts
251
- import { createSign as createSign2 } from "node:crypto";
252
- var FCM_API_URL = "https://fcm.googleapis.com/v1/projects";
253
- var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
254
- var TOKEN_EXPIRY_MS2 = 55 * 60 * 1000;
255
-
256
- class FCMClient {
257
- config;
258
- accessToken = null;
259
- tokenExpiresAt = 0;
260
- constructor(config) {
261
- this.config = config;
262
- }
263
- static fromServiceAccount(serviceAccount) {
264
- return new FCMClient({
265
- projectId: serviceAccount.project_id,
266
- clientEmail: serviceAccount.client_email,
267
- privateKey: serviceAccount.private_key
268
- });
269
- }
270
- generateJWT() {
271
- const now = Math.floor(Date.now() / 1000);
272
- const exp = now + 3600;
273
- const header = {
274
- alg: "RS256",
275
- typ: "JWT"
276
- };
277
- const payload = {
278
- iss: this.config.clientEmail,
279
- sub: this.config.clientEmail,
280
- aud: GOOGLE_TOKEN_URL,
281
- iat: now,
282
- exp,
283
- scope: "https://www.googleapis.com/auth/firebase.messaging"
284
- };
285
- const encodedHeader = Buffer.from(JSON.stringify(header)).toString("base64url");
286
- const encodedPayload = Buffer.from(JSON.stringify(payload)).toString("base64url");
287
- const signatureInput = `${encodedHeader}.${encodedPayload}`;
288
- const sign = createSign2("SHA256");
289
- sign.update(signatureInput);
290
- const signature = sign.sign(this.config.privateKey, "base64url");
291
- return `${signatureInput}.${signature}`;
292
- }
293
- async getAccessToken() {
294
- if (this.accessToken && Date.now() < this.tokenExpiresAt) {
295
- return this.accessToken;
296
- }
297
- const jwt = this.generateJWT();
298
- const response = await fetch(GOOGLE_TOKEN_URL, {
299
- method: "POST",
300
- headers: {
301
- "Content-Type": "application/x-www-form-urlencoded"
302
- },
303
- body: new URLSearchParams({
304
- grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
305
- assertion: jwt
306
- }).toString()
307
- });
308
- if (!response.ok) {
309
- const errorText = await response.text();
310
- throw new Error(`Failed to get access token: ${errorText}`);
311
- }
312
- const data = await response.json();
313
- this.accessToken = data.access_token;
314
- this.tokenExpiresAt = Date.now() + TOKEN_EXPIRY_MS2;
315
- return this.accessToken;
316
- }
317
- buildMessage(notification) {
318
- const message = {};
319
- if (notification.token) {
320
- message.token = notification.token;
321
- } else if (notification.topic) {
322
- message.topic = notification.topic;
323
- } else if (notification.condition) {
324
- message.condition = notification.condition;
325
- }
326
- if (notification.title || notification.body || notification.imageUrl) {
327
- message.notification = {};
328
- if (notification.title)
329
- message.notification.title = notification.title;
330
- if (notification.body)
331
- message.notification.body = notification.body;
332
- if (notification.imageUrl)
333
- message.notification.image = notification.imageUrl;
334
- }
335
- if (notification.data && Object.keys(notification.data).length > 0) {
336
- message.data = notification.data;
337
- }
338
- if (notification.android) {
339
- message.android = {
340
- priority: notification.android.priority || "high"
341
- };
342
- if (notification.android.ttl) {
343
- message.android.ttl = `${notification.android.ttl}s`;
344
- }
345
- if (notification.android.collapseKey) {
346
- message.android.collapse_key = notification.android.collapseKey;
347
- }
348
- if (notification.android.directBootOk) {
349
- message.android.direct_boot_ok = notification.android.directBootOk;
350
- }
351
- const androidNotification = {};
352
- if (notification.android.channelId)
353
- androidNotification.channel_id = notification.android.channelId;
354
- if (notification.android.icon)
355
- androidNotification.icon = notification.android.icon;
356
- if (notification.android.color)
357
- androidNotification.color = notification.android.color;
358
- if (notification.android.sound)
359
- androidNotification.sound = notification.android.sound;
360
- if (notification.android.clickAction)
361
- androidNotification.click_action = notification.android.clickAction;
362
- if (notification.android.tag)
363
- androidNotification.tag = notification.android.tag;
364
- if (notification.android.visibility)
365
- androidNotification.visibility = notification.android.visibility;
366
- if (notification.android.notificationCount !== undefined) {
367
- androidNotification.notification_count = notification.android.notificationCount;
368
- }
369
- if (Object.keys(androidNotification).length > 0) {
370
- message.android.notification = androidNotification;
371
- }
372
- }
373
- if (notification.webpush) {
374
- message.webpush = notification.webpush;
375
- }
376
- if (notification.apns) {
377
- message.apns = notification.apns;
378
- }
379
- if (notification.fcmOptions) {
380
- message.fcm_options = notification.fcmOptions;
381
- }
382
- return { message };
383
- }
384
- async send(notification) {
385
- try {
386
- const accessToken = await this.getAccessToken();
387
- const payload = this.buildMessage(notification);
388
- const response = await fetch(`${FCM_API_URL}/${this.config.projectId}/messages:send`, {
389
- method: "POST",
390
- headers: {
391
- Authorization: `Bearer ${accessToken}`,
392
- "Content-Type": "application/json"
393
- },
394
- body: JSON.stringify(payload)
395
- });
396
- const data = await response.json();
397
- if (response.ok) {
398
- return {
399
- success: true,
400
- messageId: data.name
401
- };
402
- } else {
403
- return {
404
- success: false,
405
- error: data.error?.message || "Unknown error",
406
- errorCode: data.error?.status
407
- };
408
- }
409
- } catch (error) {
410
- return {
411
- success: false,
412
- error: error.message
413
- };
414
- }
415
- }
416
- async sendBatch(tokens, notification, options) {
417
- const concurrency = options?.concurrency || 10;
418
- const results = [];
419
- for (let i = 0;i < tokens.length; i += concurrency) {
420
- const batch = tokens.slice(i, i + concurrency);
421
- const batchPromises = batch.map(async (token) => {
422
- const result = await this.send({ ...notification, token });
423
- return { ...result, token };
424
- });
425
- const batchResults = await Promise.all(batchPromises);
426
- results.push(...batchResults);
427
- }
428
- return {
429
- sent: results.filter((r) => r.success).length,
430
- failed: results.filter((r) => !r.success).length,
431
- results
432
- };
433
- }
434
- async sendToTopic(topic, notification) {
435
- return this.send({ ...notification, topic });
436
- }
437
- async sendToCondition(condition, notification) {
438
- return this.send({ ...notification, condition });
439
- }
440
- async sendSimple(token, title, body, data) {
441
- return this.send({
442
- token,
443
- title,
444
- body,
445
- data
446
- });
447
- }
448
- async sendSilent(token, data) {
449
- return this.send({
450
- token,
451
- data,
452
- android: {
453
- priority: "high"
454
- }
455
- });
456
- }
457
- async subscribeToTopic(tokens, topic) {
458
- try {
459
- const accessToken = await this.getAccessToken();
460
- const response = await fetch(`https://iid.googleapis.com/iid/v1:batchAdd`, {
461
- method: "POST",
462
- headers: {
463
- Authorization: `Bearer ${accessToken}`,
464
- "Content-Type": "application/json"
465
- },
466
- body: JSON.stringify({
467
- to: `/topics/${topic}`,
468
- registration_tokens: tokens
469
- })
470
- });
471
- if (response.ok) {
472
- return { success: true };
473
- } else {
474
- const data = await response.json();
475
- return { success: false, error: data.error?.message || "Failed to subscribe" };
476
- }
477
- } catch (error) {
478
- return { success: false, error: error.message };
479
- }
480
- }
481
- async unsubscribeFromTopic(tokens, topic) {
482
- try {
483
- const accessToken = await this.getAccessToken();
484
- const response = await fetch(`https://iid.googleapis.com/iid/v1:batchRemove`, {
485
- method: "POST",
486
- headers: {
487
- Authorization: `Bearer ${accessToken}`,
488
- "Content-Type": "application/json"
489
- },
490
- body: JSON.stringify({
491
- to: `/topics/${topic}`,
492
- registration_tokens: tokens
493
- })
494
- });
495
- if (response.ok) {
496
- return { success: true };
497
- } else {
498
- const data = await response.json();
499
- return { success: false, error: data.error?.message || "Failed to unsubscribe" };
500
- }
501
- } catch (error) {
502
- return { success: false, error: error.message };
503
- }
504
- }
505
- }
506
- export {
507
- FCMClient,
508
- APNsClient
509
- };
1
+ import"../chunk-xt3s24vr.js";import*as K from"node:http2";import{createSign as U}from"node:crypto";var q="api.push.apple.com",D="api.sandbox.push.apple.com",M=2700000;class E{config;token=null;tokenGeneratedAt=0;client=null;host;constructor(z){this.config=z,this.host=z.production?q:D}generateToken(){let z=Math.floor(Date.now()/1000);if(this.token&&Date.now()-this.tokenGeneratedAt<M)return this.token;let J={alg:"ES256",kid:this.config.keyId},Q={iss:this.config.teamId,iat:z},V=Buffer.from(JSON.stringify(J)).toString("base64url"),W=Buffer.from(JSON.stringify(Q)).toString("base64url"),Z=`${V}.${W}`,$=U("SHA256");$.update(Z);let B=$.sign(this.config.privateKey),x=this.derToRaw(B).toString("base64url");return this.token=`${Z}.${x}`,this.tokenGeneratedAt=Date.now(),this.token}derToRaw(z){let J=2;if(z[J]!==2)throw Error("Invalid DER signature: expected 0x02 for R");J++;let Q=z[J];J++;let V=z.subarray(J,J+Q);if(J+=Q,z[J]!==2)throw Error("Invalid DER signature: expected 0x02 for S");J++;let W=z[J];J++;let Z=z.subarray(J,J+W);if(V[0]===0&&V.length===33)V=V.subarray(1);if(Z[0]===0&&Z.length===33)Z=Z.subarray(1);let $=Buffer.alloc(64);return V.copy($,32-V.length),Z.copy($,64-Z.length),$}async getClient(){if(this.client&&!this.client.destroyed)return this.client;return new Promise((z,J)=>{this.client=K.connect(`https://${this.host}`),this.client.on("error",(Q)=>{J(Q)}),this.client.on("connect",()=>{z(this.client)}),this.client.on("close",()=>{this.client=null})})}buildPayload(z){let J={};if(z.title||z.body||z.subtitle){if(J.alert={},z.title)J.alert.title=z.title;if(z.subtitle)J.alert.subtitle=z.subtitle;if(z.body)J.alert.body=z.body}if(z.badge!==void 0)J.badge=z.badge;if(z.sound!==void 0)J.sound=z.sound;if(z.category)J.category=z.category;if(z.threadId)J["thread-id"]=z.threadId;if(z.contentAvailable)J["content-available"]=1;if(z.mutableContent)J["mutable-content"]=1;if(z.targetContentId)J["target-content-id"]=z.targetContentId;let Q={aps:J};if(z.data)Object.assign(Q,z.data);return Q}async send(z){try{let J=await this.getClient(),Q=this.generateToken(),V=JSON.stringify(this.buildPayload(z)),W={":method":"POST",":path":`/3/device/${z.deviceToken}`,authorization:`bearer ${Q}`,"apns-topic":this.config.bundleId,"apns-push-type":z.pushType||"alert","apns-priority":String(z.priority||10)};if(z.expiration!==void 0)W["apns-expiration"]=String(z.expiration);if(z.collapseId)W["apns-collapse-id"]=z.collapseId;return new Promise((Z)=>{let $=J.request(W),B="",j=0,x;$.on("response",(Y)=>{j=Y[":status"],x=Y["apns-id"]}),$.on("data",(Y)=>{B+=Y.toString()}),$.on("end",()=>{if(j===200)Z({success:!0,deviceToken:z.deviceToken,apnsId:x,statusCode:j});else{let Y="Unknown error",X,w;if(B)try{let G=JSON.parse(B);X=G.reason,w=G.timestamp,Y=X||Y}catch{Y=B}Z({success:!1,deviceToken:z.deviceToken,apnsId:x,statusCode:j,error:Y,reason:X,timestamp:w})}}),$.on("error",(Y)=>{Z({success:!1,deviceToken:z.deviceToken,error:Y.message})}),$.write(V),$.end()})}catch(J){return{success:!1,deviceToken:z.deviceToken,error:J.message}}}async sendBatch(z,J){let Q=J?.concurrency||10,V=[];for(let W=0;W<z.length;W+=Q){let Z=z.slice(W,W+Q),$=await Promise.all(Z.map((B)=>this.send(B)));V.push(...$)}return{sent:V.filter((W)=>W.success).length,failed:V.filter((W)=>!W.success).length,results:V}}async sendSimple(z,J,Q,V){return this.send({deviceToken:z,title:J,body:Q,data:V})}async sendSilent(z,J){return this.send({deviceToken:z,contentAvailable:!0,pushType:"background",priority:5,data:J})}close(){if(this.client)this.client.close(),this.client=null;this.token=null,this.tokenGeneratedAt=0}}import{createSign as L}from"node:crypto";var R="https://fcm.googleapis.com/v1/projects",F="https://oauth2.googleapis.com/token",b=3300000;class H{config;accessToken=null;tokenExpiresAt=0;constructor(z){this.config=z}static fromServiceAccount(z){return new H({projectId:z.project_id,clientEmail:z.client_email,privateKey:z.private_key})}generateJWT(){let z=Math.floor(Date.now()/1000),J=z+3600,Q={alg:"RS256",typ:"JWT"},V={iss:this.config.clientEmail,sub:this.config.clientEmail,aud:F,iat:z,exp:J,scope:"https://www.googleapis.com/auth/firebase.messaging"},W=Buffer.from(JSON.stringify(Q)).toString("base64url"),Z=Buffer.from(JSON.stringify(V)).toString("base64url"),$=`${W}.${Z}`,B=L("SHA256");B.update($);let j=B.sign(this.config.privateKey,"base64url");return`${$}.${j}`}async getAccessToken(){if(this.accessToken&&Date.now()<this.tokenExpiresAt)return this.accessToken;let z=this.generateJWT(),J=await fetch(F,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"urn:ietf:params:oauth:grant-type:jwt-bearer",assertion:z}).toString()});if(!J.ok){let V=await J.text();throw Error(`Failed to get access token: ${V}`)}let Q=await J.json();return this.accessToken=Q.access_token,this.tokenExpiresAt=Date.now()+b,this.accessToken}buildMessage(z){let J={};if(z.token)J.token=z.token;else if(z.topic)J.topic=z.topic;else if(z.condition)J.condition=z.condition;if(z.title||z.body||z.imageUrl){if(J.notification={},z.title)J.notification.title=z.title;if(z.body)J.notification.body=z.body;if(z.imageUrl)J.notification.image=z.imageUrl}if(z.data&&Object.keys(z.data).length>0)J.data=z.data;if(z.android){if(J.android={priority:z.android.priority||"high"},z.android.ttl)J.android.ttl=`${z.android.ttl}s`;if(z.android.collapseKey)J.android.collapse_key=z.android.collapseKey;if(z.android.directBootOk)J.android.direct_boot_ok=z.android.directBootOk;let Q={};if(z.android.channelId)Q.channel_id=z.android.channelId;if(z.android.icon)Q.icon=z.android.icon;if(z.android.color)Q.color=z.android.color;if(z.android.sound)Q.sound=z.android.sound;if(z.android.clickAction)Q.click_action=z.android.clickAction;if(z.android.tag)Q.tag=z.android.tag;if(z.android.visibility)Q.visibility=z.android.visibility;if(z.android.notificationCount!==void 0)Q.notification_count=z.android.notificationCount;if(Object.keys(Q).length>0)J.android.notification=Q}if(z.webpush)J.webpush=z.webpush;if(z.apns)J.apns=z.apns;if(z.fcmOptions)J.fcm_options=z.fcmOptions;return{message:J}}async send(z){try{let J=await this.getAccessToken(),Q=this.buildMessage(z),V=await fetch(`${R}/${this.config.projectId}/messages:send`,{method:"POST",headers:{Authorization:`Bearer ${J}`,"Content-Type":"application/json"},body:JSON.stringify(Q)}),W=await V.json();if(V.ok)return{success:!0,messageId:W.name};else return{success:!1,error:W.error?.message||"Unknown error",errorCode:W.error?.status}}catch(J){return{success:!1,error:J.message}}}async sendBatch(z,J,Q){let V=Q?.concurrency||10,W=[];for(let Z=0;Z<z.length;Z+=V){let B=z.slice(Z,Z+V).map(async(x)=>{return{...await this.send({...J,token:x}),token:x}}),j=await Promise.all(B);W.push(...j)}return{sent:W.filter((Z)=>Z.success).length,failed:W.filter((Z)=>!Z.success).length,results:W}}async sendToTopic(z,J){return this.send({...J,topic:z})}async sendToCondition(z,J){return this.send({...J,condition:z})}async sendSimple(z,J,Q,V){return this.send({token:z,title:J,body:Q,data:V})}async sendSilent(z,J){return this.send({token:z,data:J,android:{priority:"high"}})}async subscribeToTopic(z,J){try{let Q=await this.getAccessToken(),V=await fetch("https://iid.googleapis.com/iid/v1:batchAdd",{method:"POST",headers:{Authorization:`Bearer ${Q}`,"Content-Type":"application/json"},body:JSON.stringify({to:`/topics/${J}`,registration_tokens:z})});if(V.ok)return{success:!0};else return{success:!1,error:(await V.json()).error?.message||"Failed to subscribe"}}catch(Q){return{success:!1,error:Q.message}}}async unsubscribeFromTopic(z,J){try{let Q=await this.getAccessToken(),V=await fetch("https://iid.googleapis.com/iid/v1:batchRemove",{method:"POST",headers:{Authorization:`Bearer ${Q}`,"Content-Type":"application/json"},body:JSON.stringify({to:`/topics/${J}`,registration_tokens:z})});if(V.ok)return{success:!0};else return{success:!1,error:(await V.json()).error?.message||"Failed to unsubscribe"}}catch(Q){return{success:!1,error:Q.message}}}}export{H as FCMClient,E as APNsClient};