stellar-drive 1.0.0

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 (246) hide show
  1. package/README.md +607 -0
  2. package/dist/actions/remoteChange.d.ts +204 -0
  3. package/dist/actions/remoteChange.d.ts.map +1 -0
  4. package/dist/actions/remoteChange.js +424 -0
  5. package/dist/actions/remoteChange.js.map +1 -0
  6. package/dist/actions/truncateTooltip.d.ts +56 -0
  7. package/dist/actions/truncateTooltip.d.ts.map +1 -0
  8. package/dist/actions/truncateTooltip.js +312 -0
  9. package/dist/actions/truncateTooltip.js.map +1 -0
  10. package/dist/auth/crypto.d.ts +41 -0
  11. package/dist/auth/crypto.d.ts.map +1 -0
  12. package/dist/auth/crypto.js +50 -0
  13. package/dist/auth/crypto.js.map +1 -0
  14. package/dist/auth/deviceVerification.d.ts +283 -0
  15. package/dist/auth/deviceVerification.d.ts.map +1 -0
  16. package/dist/auth/deviceVerification.js +575 -0
  17. package/dist/auth/deviceVerification.js.map +1 -0
  18. package/dist/auth/displayUtils.d.ts +98 -0
  19. package/dist/auth/displayUtils.d.ts.map +1 -0
  20. package/dist/auth/displayUtils.js +145 -0
  21. package/dist/auth/displayUtils.js.map +1 -0
  22. package/dist/auth/loginGuard.d.ts +134 -0
  23. package/dist/auth/loginGuard.d.ts.map +1 -0
  24. package/dist/auth/loginGuard.js +276 -0
  25. package/dist/auth/loginGuard.js.map +1 -0
  26. package/dist/auth/offlineCredentials.d.ts +105 -0
  27. package/dist/auth/offlineCredentials.d.ts.map +1 -0
  28. package/dist/auth/offlineCredentials.js +176 -0
  29. package/dist/auth/offlineCredentials.js.map +1 -0
  30. package/dist/auth/offlineSession.d.ts +96 -0
  31. package/dist/auth/offlineSession.d.ts.map +1 -0
  32. package/dist/auth/offlineSession.js +145 -0
  33. package/dist/auth/offlineSession.js.map +1 -0
  34. package/dist/auth/resolveAuthState.d.ts +85 -0
  35. package/dist/auth/resolveAuthState.d.ts.map +1 -0
  36. package/dist/auth/resolveAuthState.js +249 -0
  37. package/dist/auth/resolveAuthState.js.map +1 -0
  38. package/dist/auth/singleUser.d.ts +498 -0
  39. package/dist/auth/singleUser.d.ts.map +1 -0
  40. package/dist/auth/singleUser.js +1282 -0
  41. package/dist/auth/singleUser.js.map +1 -0
  42. package/dist/bin/commands.d.ts +14 -0
  43. package/dist/bin/commands.d.ts.map +1 -0
  44. package/dist/bin/commands.js +68 -0
  45. package/dist/bin/commands.js.map +1 -0
  46. package/dist/bin/install-pwa.d.ts +41 -0
  47. package/dist/bin/install-pwa.d.ts.map +1 -0
  48. package/dist/bin/install-pwa.js +4594 -0
  49. package/dist/bin/install-pwa.js.map +1 -0
  50. package/dist/config.d.ts +249 -0
  51. package/dist/config.d.ts.map +1 -0
  52. package/dist/config.js +395 -0
  53. package/dist/config.js.map +1 -0
  54. package/dist/conflicts.d.ts +306 -0
  55. package/dist/conflicts.d.ts.map +1 -0
  56. package/dist/conflicts.js +807 -0
  57. package/dist/conflicts.js.map +1 -0
  58. package/dist/crdt/awareness.d.ts +128 -0
  59. package/dist/crdt/awareness.d.ts.map +1 -0
  60. package/dist/crdt/awareness.js +284 -0
  61. package/dist/crdt/awareness.js.map +1 -0
  62. package/dist/crdt/channel.d.ts +165 -0
  63. package/dist/crdt/channel.d.ts.map +1 -0
  64. package/dist/crdt/channel.js +522 -0
  65. package/dist/crdt/channel.js.map +1 -0
  66. package/dist/crdt/config.d.ts +58 -0
  67. package/dist/crdt/config.d.ts.map +1 -0
  68. package/dist/crdt/config.js +123 -0
  69. package/dist/crdt/config.js.map +1 -0
  70. package/dist/crdt/helpers.d.ts +104 -0
  71. package/dist/crdt/helpers.d.ts.map +1 -0
  72. package/dist/crdt/helpers.js +116 -0
  73. package/dist/crdt/helpers.js.map +1 -0
  74. package/dist/crdt/offline.d.ts +58 -0
  75. package/dist/crdt/offline.d.ts.map +1 -0
  76. package/dist/crdt/offline.js +130 -0
  77. package/dist/crdt/offline.js.map +1 -0
  78. package/dist/crdt/persistence.d.ts +65 -0
  79. package/dist/crdt/persistence.d.ts.map +1 -0
  80. package/dist/crdt/persistence.js +171 -0
  81. package/dist/crdt/persistence.js.map +1 -0
  82. package/dist/crdt/provider.d.ts +109 -0
  83. package/dist/crdt/provider.d.ts.map +1 -0
  84. package/dist/crdt/provider.js +543 -0
  85. package/dist/crdt/provider.js.map +1 -0
  86. package/dist/crdt/store.d.ts +111 -0
  87. package/dist/crdt/store.d.ts.map +1 -0
  88. package/dist/crdt/store.js +158 -0
  89. package/dist/crdt/store.js.map +1 -0
  90. package/dist/crdt/types.d.ts +281 -0
  91. package/dist/crdt/types.d.ts.map +1 -0
  92. package/dist/crdt/types.js +26 -0
  93. package/dist/crdt/types.js.map +1 -0
  94. package/dist/data.d.ts +502 -0
  95. package/dist/data.d.ts.map +1 -0
  96. package/dist/data.js +862 -0
  97. package/dist/data.js.map +1 -0
  98. package/dist/database.d.ts +153 -0
  99. package/dist/database.d.ts.map +1 -0
  100. package/dist/database.js +325 -0
  101. package/dist/database.js.map +1 -0
  102. package/dist/debug.d.ts +87 -0
  103. package/dist/debug.d.ts.map +1 -0
  104. package/dist/debug.js +135 -0
  105. package/dist/debug.js.map +1 -0
  106. package/dist/demo.d.ts +131 -0
  107. package/dist/demo.d.ts.map +1 -0
  108. package/dist/demo.js +168 -0
  109. package/dist/demo.js.map +1 -0
  110. package/dist/deviceId.d.ts +47 -0
  111. package/dist/deviceId.d.ts.map +1 -0
  112. package/dist/deviceId.js +106 -0
  113. package/dist/deviceId.js.map +1 -0
  114. package/dist/diagnostics.d.ts +292 -0
  115. package/dist/diagnostics.d.ts.map +1 -0
  116. package/dist/diagnostics.js +378 -0
  117. package/dist/diagnostics.js.map +1 -0
  118. package/dist/engine.d.ts +230 -0
  119. package/dist/engine.d.ts.map +1 -0
  120. package/dist/engine.js +2636 -0
  121. package/dist/engine.js.map +1 -0
  122. package/dist/entries/actions.d.ts +16 -0
  123. package/dist/entries/actions.d.ts.map +1 -0
  124. package/dist/entries/actions.js +29 -0
  125. package/dist/entries/actions.js.map +1 -0
  126. package/dist/entries/auth.d.ts +19 -0
  127. package/dist/entries/auth.d.ts.map +1 -0
  128. package/dist/entries/auth.js +50 -0
  129. package/dist/entries/auth.js.map +1 -0
  130. package/dist/entries/config.d.ts +15 -0
  131. package/dist/entries/config.d.ts.map +1 -0
  132. package/dist/entries/config.js +20 -0
  133. package/dist/entries/config.js.map +1 -0
  134. package/dist/entries/crdt.d.ts +32 -0
  135. package/dist/entries/crdt.d.ts.map +1 -0
  136. package/dist/entries/crdt.js +52 -0
  137. package/dist/entries/crdt.js.map +1 -0
  138. package/dist/entries/kit.d.ts +22 -0
  139. package/dist/entries/kit.d.ts.map +1 -0
  140. package/dist/entries/kit.js +58 -0
  141. package/dist/entries/kit.js.map +1 -0
  142. package/dist/entries/stores.d.ts +22 -0
  143. package/dist/entries/stores.d.ts.map +1 -0
  144. package/dist/entries/stores.js +57 -0
  145. package/dist/entries/stores.js.map +1 -0
  146. package/dist/entries/types.d.ts +23 -0
  147. package/dist/entries/types.d.ts.map +1 -0
  148. package/dist/entries/types.js +12 -0
  149. package/dist/entries/types.js.map +1 -0
  150. package/dist/entries/utils.d.ts +12 -0
  151. package/dist/entries/utils.d.ts.map +1 -0
  152. package/dist/entries/utils.js +42 -0
  153. package/dist/entries/utils.js.map +1 -0
  154. package/dist/entries/vite.d.ts +20 -0
  155. package/dist/entries/vite.d.ts.map +1 -0
  156. package/dist/entries/vite.js +26 -0
  157. package/dist/entries/vite.js.map +1 -0
  158. package/dist/index.d.ts +77 -0
  159. package/dist/index.d.ts.map +1 -0
  160. package/dist/index.js +234 -0
  161. package/dist/index.js.map +1 -0
  162. package/dist/kit/auth.d.ts +80 -0
  163. package/dist/kit/auth.d.ts.map +1 -0
  164. package/dist/kit/auth.js +75 -0
  165. package/dist/kit/auth.js.map +1 -0
  166. package/dist/kit/confirm.d.ts +111 -0
  167. package/dist/kit/confirm.d.ts.map +1 -0
  168. package/dist/kit/confirm.js +169 -0
  169. package/dist/kit/confirm.js.map +1 -0
  170. package/dist/kit/loads.d.ts +187 -0
  171. package/dist/kit/loads.d.ts.map +1 -0
  172. package/dist/kit/loads.js +208 -0
  173. package/dist/kit/loads.js.map +1 -0
  174. package/dist/kit/server.d.ts +175 -0
  175. package/dist/kit/server.d.ts.map +1 -0
  176. package/dist/kit/server.js +297 -0
  177. package/dist/kit/server.js.map +1 -0
  178. package/dist/kit/sw.d.ts +176 -0
  179. package/dist/kit/sw.d.ts.map +1 -0
  180. package/dist/kit/sw.js +320 -0
  181. package/dist/kit/sw.js.map +1 -0
  182. package/dist/queue.d.ts +306 -0
  183. package/dist/queue.d.ts.map +1 -0
  184. package/dist/queue.js +925 -0
  185. package/dist/queue.js.map +1 -0
  186. package/dist/realtime.d.ts +280 -0
  187. package/dist/realtime.d.ts.map +1 -0
  188. package/dist/realtime.js +1031 -0
  189. package/dist/realtime.js.map +1 -0
  190. package/dist/runtime/runtimeConfig.d.ts +110 -0
  191. package/dist/runtime/runtimeConfig.d.ts.map +1 -0
  192. package/dist/runtime/runtimeConfig.js +260 -0
  193. package/dist/runtime/runtimeConfig.js.map +1 -0
  194. package/dist/schema.d.ts +150 -0
  195. package/dist/schema.d.ts.map +1 -0
  196. package/dist/schema.js +891 -0
  197. package/dist/schema.js.map +1 -0
  198. package/dist/stores/authState.d.ts +204 -0
  199. package/dist/stores/authState.d.ts.map +1 -0
  200. package/dist/stores/authState.js +336 -0
  201. package/dist/stores/authState.js.map +1 -0
  202. package/dist/stores/factories.d.ts +140 -0
  203. package/dist/stores/factories.d.ts.map +1 -0
  204. package/dist/stores/factories.js +157 -0
  205. package/dist/stores/factories.js.map +1 -0
  206. package/dist/stores/network.d.ts +48 -0
  207. package/dist/stores/network.d.ts.map +1 -0
  208. package/dist/stores/network.js +261 -0
  209. package/dist/stores/network.js.map +1 -0
  210. package/dist/stores/remoteChanges.d.ts +417 -0
  211. package/dist/stores/remoteChanges.d.ts.map +1 -0
  212. package/dist/stores/remoteChanges.js +626 -0
  213. package/dist/stores/remoteChanges.js.map +1 -0
  214. package/dist/stores/sync.d.ts +165 -0
  215. package/dist/stores/sync.d.ts.map +1 -0
  216. package/dist/stores/sync.js +275 -0
  217. package/dist/stores/sync.js.map +1 -0
  218. package/dist/supabase/auth.d.ts +219 -0
  219. package/dist/supabase/auth.d.ts.map +1 -0
  220. package/dist/supabase/auth.js +459 -0
  221. package/dist/supabase/auth.js.map +1 -0
  222. package/dist/supabase/client.d.ts +88 -0
  223. package/dist/supabase/client.d.ts.map +1 -0
  224. package/dist/supabase/client.js +313 -0
  225. package/dist/supabase/client.js.map +1 -0
  226. package/dist/supabase/validate.d.ts +118 -0
  227. package/dist/supabase/validate.d.ts.map +1 -0
  228. package/dist/supabase/validate.js +208 -0
  229. package/dist/supabase/validate.js.map +1 -0
  230. package/dist/sw/build/vite-plugin.d.ts +149 -0
  231. package/dist/sw/build/vite-plugin.d.ts.map +1 -0
  232. package/dist/sw/build/vite-plugin.js +517 -0
  233. package/dist/sw/build/vite-plugin.js.map +1 -0
  234. package/dist/sw/sw.js +664 -0
  235. package/dist/types.d.ts +363 -0
  236. package/dist/types.d.ts.map +1 -0
  237. package/dist/types.js +18 -0
  238. package/dist/types.js.map +1 -0
  239. package/dist/utils.d.ts +85 -0
  240. package/dist/utils.d.ts.map +1 -0
  241. package/dist/utils.js +156 -0
  242. package/dist/utils.js.map +1 -0
  243. package/package.json +117 -0
  244. package/src/components/DeferredChangesBanner.svelte +477 -0
  245. package/src/components/DemoBanner.svelte +110 -0
  246. package/src/components/SyncStatus.svelte +1732 -0
@@ -0,0 +1,297 @@
1
+ /**
2
+ * @fileoverview Server-side API helpers for SvelteKit route handlers.
3
+ *
4
+ * This module extracts reusable backend logic so scaffolded API routes can be
5
+ * thin wrappers around these helpers. It provides three main capabilities:
6
+ *
7
+ * - **Server config reading** — reads Supabase credentials from environment
8
+ * variables at runtime (`getServerConfig`)
9
+ * - **Vercel deployment** — upserts env vars and triggers production
10
+ * redeployments via the Vercel REST API (`deployToVercel`)
11
+ * - **Credential validation** — factory for a SvelteKit POST handler that
12
+ * validates Supabase credentials (`createValidateHandler`)
13
+ *
14
+ * All Vercel API interactions use a create-or-update (upsert) strategy for
15
+ * environment variables, and support both git-based and clone-based
16
+ * redeployment strategies for maximum compatibility.
17
+ *
18
+ * @module kit/server
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * // In /api/config/+server.ts
23
+ * import { getServerConfig } from 'stellar-drive/kit/server';
24
+ * export function GET() {
25
+ * return new Response(JSON.stringify(getServerConfig()));
26
+ * }
27
+ * ```
28
+ *
29
+ * @see {@link https://vercel.com/docs/rest-api} for Vercel API reference
30
+ * @see {@link validateSupabaseCredentials} in `supabase/validate.ts`
31
+ */
32
+ // =============================================================================
33
+ // HELPERS — Vercel API Utilities
34
+ // =============================================================================
35
+ /**
36
+ * Low-level wrapper around the Vercel REST API.
37
+ *
38
+ * Handles authentication headers and JSON body serialization for all
39
+ * Vercel API calls. This is an internal helper — not exported.
40
+ *
41
+ * @param path - The API path (appended to `https://api.vercel.com`).
42
+ * @param token - The Vercel bearer token for authorization.
43
+ * @param method - HTTP method (defaults to `'GET'`).
44
+ * @param body - Optional request body, serialized to JSON.
45
+ *
46
+ * @returns The raw `Response` from the Vercel API.
47
+ *
48
+ * @throws {TypeError} If the `fetch` call itself fails (e.g. network error).
49
+ */
50
+ async function vercelApi(path, token, method = 'GET', body) {
51
+ return fetch(`https://api.vercel.com${path}`, {
52
+ method,
53
+ headers: {
54
+ Authorization: `Bearer ${token}`,
55
+ 'Content-Type': 'application/json'
56
+ },
57
+ body: body ? JSON.stringify(body) : undefined
58
+ });
59
+ }
60
+ /**
61
+ * Creates or updates a single environment variable on a Vercel project.
62
+ *
63
+ * Implements an upsert strategy:
64
+ * 1. Attempt to create via `POST /v10/projects/:id/env`.
65
+ * 2. If Vercel returns `ENV_ALREADY_EXISTS`, list all env vars to find
66
+ * the existing entry's ID, then patch it with the new value.
67
+ *
68
+ * This two-step approach is necessary because Vercel's create endpoint
69
+ * does not support an "upsert" mode — it always fails if the key exists.
70
+ *
71
+ * @param projectId - The Vercel project ID.
72
+ * @param token - The Vercel bearer token.
73
+ * @param key - The environment variable name to set.
74
+ * @param value - The environment variable value.
75
+ *
76
+ * @throws {Error} If the create fails for a reason other than already-exists,
77
+ * or if the list/patch fallback also fails.
78
+ */
79
+ async function setEnvVar(projectId, token, key, value) {
80
+ const createRes = await vercelApi(`/v10/projects/${projectId}/env`, token, 'POST', {
81
+ key,
82
+ value,
83
+ target: ['production', 'preview', 'development'],
84
+ type: 'plain'
85
+ });
86
+ if (createRes.ok)
87
+ return;
88
+ const createData = await createRes.json();
89
+ const errorCode = createData.error?.code || '';
90
+ const errorMessage = createData.error?.message || '';
91
+ /* If the variable already exists, fall through to the update path.
92
+ Vercel may report this via error code or message text depending
93
+ on the API version, so we check both. */
94
+ if (errorCode === 'ENV_ALREADY_EXISTS' || errorMessage.includes('already exists')) {
95
+ /* List all env vars to find the existing entry's ID — Vercel requires
96
+ the entry ID for PATCH operations, not the key name. */
97
+ const listRes = await vercelApi(`/v9/projects/${projectId}/env`, token);
98
+ if (!listRes.ok) {
99
+ throw new Error(`Failed to list env vars: ${listRes.statusText}`);
100
+ }
101
+ const listData = await listRes.json();
102
+ const existing = listData.envs?.find((e) => e.key === key);
103
+ if (existing) {
104
+ const updateRes = await vercelApi(`/v9/projects/${projectId}/env/${existing.id}`, token, 'PATCH', { value });
105
+ if (!updateRes.ok) {
106
+ throw new Error(`Failed to update env var ${key}: ${updateRes.statusText}`);
107
+ }
108
+ }
109
+ else {
110
+ /* Edge case: Vercel says the var exists but it's not in the list.
111
+ This can happen with env var scoping issues. */
112
+ throw new Error(`Env var ${key} reported as existing but not found in list`);
113
+ }
114
+ }
115
+ else {
116
+ throw new Error(`Failed to create env var ${key}: ${createData.error?.message || createRes.statusText}`);
117
+ }
118
+ }
119
+ // =============================================================================
120
+ // PUBLIC API
121
+ // =============================================================================
122
+ /**
123
+ * Reads Supabase configuration from `process.env` at runtime.
124
+ *
125
+ * Checks for the presence of both `PUBLIC_SUPABASE_URL` and
126
+ * `PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY` environment variables.
127
+ * Returns `{ configured: true }` with the values when both exist,
128
+ * or `{ configured: false }` otherwise.
129
+ *
130
+ * This is intended for use in SvelteKit server routes (e.g. `+server.ts`)
131
+ * to report configuration status to the client during the setup flow.
132
+ *
133
+ * @returns The server config status with optional Supabase credentials.
134
+ *
135
+ * @example
136
+ * ```ts
137
+ * // In /api/config/+server.ts
138
+ * import { getServerConfig } from 'stellar-drive/kit/server';
139
+ * export function GET() {
140
+ * return new Response(JSON.stringify(getServerConfig()), {
141
+ * headers: { 'Content-Type': 'application/json' }
142
+ * });
143
+ * }
144
+ * ```
145
+ *
146
+ * @see {@link ServerConfig} for the return type shape
147
+ */
148
+ export function getServerConfig() {
149
+ const supabaseUrl = process.env.PUBLIC_SUPABASE_URL || '';
150
+ const supabaseAnonKey = process.env.PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY || '';
151
+ if (supabaseUrl && supabaseAnonKey) {
152
+ return { configured: true, supabaseUrl, supabaseAnonKey };
153
+ }
154
+ return { configured: false };
155
+ }
156
+ /**
157
+ * Full Vercel deployment flow: upserts Supabase environment variables,
158
+ * then triggers a production redeployment.
159
+ *
160
+ * The deployment uses a two-strategy approach:
161
+ * - **Strategy A (preferred)**: Git-based redeployment using the repo
162
+ * metadata from Vercel's environment (`VERCEL_GIT_REPO_SLUG`, etc.).
163
+ * This triggers a fresh build from the source branch.
164
+ * - **Strategy B (fallback)**: Clone-based redeployment using an existing
165
+ * deployment ID (`VERCEL_DEPLOYMENT_ID` or `VERCEL_URL`). This
166
+ * reuses the last build artifacts with updated env vars.
167
+ *
168
+ * Both strategies target the `production` environment.
169
+ *
170
+ * @param config - The deployment configuration containing Vercel auth
171
+ * credentials, project ID, and Supabase connection values.
172
+ *
173
+ * @returns A result object indicating success/failure with an optional
174
+ * deployment URL or error message.
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * const result = await deployToVercel({
179
+ * vercelToken: 'tok_...',
180
+ * projectId: 'prj_...',
181
+ * supabaseUrl: 'https://abc.supabase.co',
182
+ * supabaseAnonKey: 'eyJ...'
183
+ * });
184
+ * if (!result.success) console.error(result.error);
185
+ * ```
186
+ *
187
+ * @see {@link DeployConfig} for the input configuration shape
188
+ * @see {@link DeployResult} for the return type shape
189
+ * @see {@link setEnvVar} for the upsert strategy used for env vars
190
+ */
191
+ export async function deployToVercel(config) {
192
+ try {
193
+ // -------------------------------------------------------------------------
194
+ // Phase 1 — Upsert environment variables
195
+ // -------------------------------------------------------------------------
196
+ await setEnvVar(config.projectId, config.vercelToken, 'PUBLIC_SUPABASE_URL', config.supabaseUrl);
197
+ await setEnvVar(config.projectId, config.vercelToken, 'PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY', config.supabaseAnonKey);
198
+ // -------------------------------------------------------------------------
199
+ // Phase 2 — Trigger production redeployment
200
+ // -------------------------------------------------------------------------
201
+ const deploymentId = process.env.VERCEL_DEPLOYMENT_ID || process.env.VERCEL_URL;
202
+ const gitRepo = process.env.VERCEL_GIT_REPO_SLUG;
203
+ const gitOwner = process.env.VERCEL_GIT_REPO_OWNER;
204
+ const gitRef = process.env.VERCEL_GIT_COMMIT_REF || 'main';
205
+ let deploymentUrl = '';
206
+ /* Strategy A — Git-based redeployment (preferred).
207
+ Uses the connected GitHub repo to trigger a fresh build from source.
208
+ Only available when Vercel has git integration metadata. */
209
+ if (gitRepo && gitOwner) {
210
+ const deployRes = await vercelApi(`/v13/deployments`, config.vercelToken, 'POST', {
211
+ name: config.projectId,
212
+ project: config.projectId,
213
+ target: 'production',
214
+ gitSource: {
215
+ type: 'github',
216
+ repoId: `${gitOwner}/${gitRepo}`,
217
+ ref: gitRef
218
+ }
219
+ });
220
+ if (deployRes.ok) {
221
+ const deployData = await deployRes.json();
222
+ deploymentUrl = deployData.url || '';
223
+ }
224
+ }
225
+ /* Strategy B — Clone current deployment (fallback).
226
+ Reuses the most recent deployment's build output with the newly
227
+ updated env vars. Used when git metadata is unavailable (e.g.
228
+ manual deploys or Vercel CLI uploads). */
229
+ if (!deploymentUrl && deploymentId) {
230
+ const redeployRes = await vercelApi(`/v13/deployments`, config.vercelToken, 'POST', {
231
+ name: config.projectId,
232
+ project: config.projectId,
233
+ target: 'production',
234
+ deploymentId
235
+ });
236
+ if (redeployRes.ok) {
237
+ const redeployData = await redeployRes.json();
238
+ deploymentUrl = redeployData.url || '';
239
+ }
240
+ }
241
+ return { success: true, deploymentUrl };
242
+ }
243
+ catch (e) {
244
+ const message = e instanceof Error ? e.message : 'Unknown error';
245
+ return { success: false, error: message };
246
+ }
247
+ }
248
+ /**
249
+ * Factory returning a SvelteKit POST handler that validates Supabase
250
+ * credentials by attempting to connect to the provided Supabase instance.
251
+ *
252
+ * The returned handler:
253
+ * 1. Parses the JSON request body for `supabaseUrl` and `supabaseAnonKey`
254
+ * 2. Validates that both fields are present (returns 400 if not)
255
+ * 3. Delegates to `validateSupabaseCredentials` for the actual check
256
+ * 4. Returns a JSON response with the validation result
257
+ *
258
+ * The `validateSupabaseCredentials` import is dynamic (`await import(...)`)
259
+ * to keep this module's dependency footprint minimal — the validation logic
260
+ * and its Supabase client dependency are only loaded when the endpoint is
261
+ * actually called.
262
+ *
263
+ * @returns An async handler function compatible with SvelteKit's
264
+ * `RequestHandler` signature for POST endpoints.
265
+ *
266
+ * @example
267
+ * ```ts
268
+ * // In /api/validate-supabase/+server.ts
269
+ * import { createValidateHandler } from 'stellar-drive/kit/server';
270
+ * export const POST = createValidateHandler();
271
+ * ```
272
+ *
273
+ * @see {@link validateSupabaseCredentials} in `supabase/validate.ts`
274
+ */
275
+ export function createValidateHandler() {
276
+ return async ({ request }) => {
277
+ /* Dynamic import keeps the Supabase client out of the module graph
278
+ until this handler is actually invoked — reduces cold start time
279
+ for routes that don't need validation. */
280
+ const { validateSupabaseCredentials } = await import('../supabase/validate.js');
281
+ try {
282
+ const { supabaseUrl, supabaseAnonKey } = await request.json();
283
+ if (!supabaseUrl || !supabaseAnonKey) {
284
+ return new Response(JSON.stringify({ valid: false, error: 'Supabase URL and Anon Key are required' }), { status: 400, headers: { 'Content-Type': 'application/json' } });
285
+ }
286
+ const result = await validateSupabaseCredentials(supabaseUrl, supabaseAnonKey);
287
+ return new Response(JSON.stringify(result), {
288
+ headers: { 'Content-Type': 'application/json' }
289
+ });
290
+ }
291
+ catch (e) {
292
+ const message = e instanceof Error ? e.message : 'Unknown error';
293
+ return new Response(JSON.stringify({ valid: false, error: `Could not connect to Supabase: ${message}` }), { headers: { 'Content-Type': 'application/json' } });
294
+ }
295
+ };
296
+ }
297
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/kit/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * @fileoverview Service worker lifecycle helpers.
3
+ *
4
+ * This module extracts SW monitoring and update logic so components and pages
5
+ * can use clean APIs without duplicating browser-specific service worker code.
6
+ * It provides three main functions:
7
+ *
8
+ * - `pollForNewServiceWorker` — active polling for a new SW after a
9
+ * deployment, useful for "checking for updates..." UI flows
10
+ * - `handleSwUpdate` — triggers `SKIP_WAITING` on a waiting SW
11
+ * and reloads the page when the new controller activates
12
+ * - `monitorSwLifecycle` — comprehensive passive monitoring that covers
13
+ * six different detection strategies for maximum reliability across
14
+ * browsers and platforms (including iOS PWA quirks)
15
+ *
16
+ * All functions include SSR guards (`typeof navigator === 'undefined'`) so
17
+ * they can be safely imported in universal (shared) SvelteKit code without
18
+ * causing server-side errors.
19
+ *
20
+ * @module kit/sw
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // In a Svelte component
25
+ * import { monitorSwLifecycle, handleSwUpdate } from 'stellar-drive/kit/sw';
26
+ *
27
+ * let showBanner = $state(false);
28
+ * const cleanup = monitorSwLifecycle({
29
+ * onUpdateAvailable: () => { showBanner = true; }
30
+ * });
31
+ * // When user clicks "Update Now":
32
+ * await handleSwUpdate();
33
+ * ```
34
+ *
35
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API}
36
+ * @see {@link debug} in `debug.ts` for the logging utility used throughout
37
+ */
38
+ /**
39
+ * Options for `pollForNewServiceWorker`.
40
+ *
41
+ * All fields are optional with sensible defaults for typical deployment
42
+ * detection scenarios.
43
+ */
44
+ export interface PollOptions {
45
+ /**
46
+ * Polling interval in milliseconds.
47
+ * @default 5000
48
+ */
49
+ intervalMs?: number;
50
+ /**
51
+ * Maximum number of polling attempts before giving up.
52
+ * With the default interval of 5s and 60 attempts, polling runs for ~5 minutes.
53
+ * @default 60
54
+ */
55
+ maxAttempts?: number;
56
+ /**
57
+ * Callback invoked when a new service worker is detected in the
58
+ * `waiting` state. Called exactly once, then polling stops automatically.
59
+ */
60
+ onFound?: () => void;
61
+ }
62
+ /**
63
+ * Callbacks for `monitorSwLifecycle`.
64
+ *
65
+ * Provides hooks into the service worker lifecycle events that the
66
+ * monitoring system detects.
67
+ */
68
+ export interface SwLifecycleCallbacks {
69
+ /**
70
+ * Called whenever an update-available condition is detected through
71
+ * any of the six monitoring strategies. May be called multiple times
72
+ * if different strategies detect the same update independently.
73
+ */
74
+ onUpdateAvailable: () => void;
75
+ }
76
+ /**
77
+ * Polls `registration.update()` until a new service worker is detected
78
+ * in the `waiting` state. Useful after triggering a deployment to detect
79
+ * when the new build is live and ready to activate.
80
+ *
81
+ * The polling loop calls `registration.update()` on each tick, which
82
+ * forces the browser to check the server for a new SW script. When a
83
+ * waiting worker is found, the `onFound` callback fires and polling
84
+ * stops automatically.
85
+ *
86
+ * @param options - Optional configuration for interval, max attempts,
87
+ * and the detection callback.
88
+ *
89
+ * @returns A cleanup function that stops polling when called. Useful
90
+ * for cleanup in Svelte's `onDestroy` or `$effect` teardown.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * const stopPolling = pollForNewServiceWorker({
95
+ * intervalMs: 3000,
96
+ * maxAttempts: 100,
97
+ * onFound: () => showUpdateBanner()
98
+ * });
99
+ *
100
+ * // Later, to stop polling early:
101
+ * stopPolling();
102
+ * ```
103
+ *
104
+ * @see {@link handleSwUpdate} for activating the waiting SW once found
105
+ */
106
+ export declare function pollForNewServiceWorker(options?: PollOptions): () => void;
107
+ /**
108
+ * Sends `SKIP_WAITING` to the waiting service worker, listens for the
109
+ * `controllerchange` event, then reloads the page to activate the new
110
+ * version.
111
+ *
112
+ * If no waiting worker is found (e.g. the update was already applied),
113
+ * falls back to a simple page reload. The `{ once: true }` listener
114
+ * option acts as a double-reload guard — the handler fires exactly once
115
+ * even if `controllerchange` is emitted multiple times during activation.
116
+ *
117
+ * @returns A promise that resolves just before the page reloads.
118
+ * In practice, the caller won't observe the resolution since
119
+ * `window.location.reload()` interrupts execution.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * // In an "Update Now" button handler
124
+ * async function onUpdateClick() {
125
+ * await handleSwUpdate();
126
+ * // Page will have reloaded by this point
127
+ * }
128
+ * ```
129
+ *
130
+ * @see {@link pollForNewServiceWorker} for detecting when an update is available
131
+ * @see {@link monitorSwLifecycle} for passive update detection
132
+ */
133
+ export declare function handleSwUpdate(): Promise<void>;
134
+ /**
135
+ * Comprehensive service worker monitoring covering all detection strategies
136
+ * for maximum reliability across browsers and platforms:
137
+ *
138
+ * 1. **Immediate check** — inspects the current registration for a
139
+ * waiting worker right away
140
+ * 2. **Delayed retries at 1s/3s** — iOS PWA sometimes needs extra time
141
+ * after app launch before the SW registration is fully populated
142
+ * 3. **`SW_INSTALLED` message listener** — listens for a custom message
143
+ * from the SW itself, posted after the `install` event completes
144
+ * 4. **`updatefound` + `statechange` tracking** — monitors the standard
145
+ * SW lifecycle events for newly installing workers
146
+ * 5. **`visibilitychange` re-check** — triggers an update check when the
147
+ * app resumes from the background (critical for iOS PWA resume)
148
+ * 6. **2-minute polling interval** — periodic fallback for long-running
149
+ * sessions where none of the event-based strategies would fire
150
+ *
151
+ * @param callbacks - Object containing the `onUpdateAvailable` callback,
152
+ * which fires whenever any strategy detects a waiting
153
+ * service worker.
154
+ *
155
+ * @returns A cleanup function that removes all event listeners, clears all
156
+ * intervals and timeouts, and stops monitoring. Should be called
157
+ * in Svelte's `onDestroy` or `$effect` teardown to prevent leaks.
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * // In a Svelte component's $effect
162
+ * $effect(() => {
163
+ * const cleanup = monitorSwLifecycle({
164
+ * onUpdateAvailable: () => {
165
+ * updateAvailable = true;
166
+ * }
167
+ * });
168
+ * return cleanup;
169
+ * });
170
+ * ```
171
+ *
172
+ * @see {@link handleSwUpdate} for activating the detected update
173
+ * @see {@link SwLifecycleCallbacks} for the callback interface
174
+ */
175
+ export declare function monitorSwLifecycle(callbacks: SwLifecycleCallbacks): () => void;
176
+ //# sourceMappingURL=sw.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sw.d.ts","sourceRoot":"","sources":["../../src/kit/sw.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAQH;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,IAAI,CAAC;CAC/B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,IAAI,CAqCzE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAuBpD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,oBAAoB,GAAG,MAAM,IAAI,CAuI9E"}