@skaile/workspaces 1.4.0 → 1.6.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 (198) hide show
  1. package/CHANGELOG.md +326 -0
  2. package/dist/app-sdk/index.js +241 -55
  3. package/dist/app-sdk/index.js.map +1 -1
  4. package/dist/app-sdk/src/app.d.ts +55 -4
  5. package/dist/app-sdk/src/app.d.ts.map +1 -1
  6. package/dist/app-sdk/src/connection-params.d.ts +117 -0
  7. package/dist/app-sdk/src/connection-params.d.ts.map +1 -0
  8. package/dist/app-sdk/src/index.d.ts +3 -2
  9. package/dist/app-sdk/src/index.d.ts.map +1 -1
  10. package/dist/app-sdk/src/transport.d.ts +9 -0
  11. package/dist/app-sdk/src/transport.d.ts.map +1 -1
  12. package/dist/app-sdk/src/ws-transport.d.ts +18 -2
  13. package/dist/app-sdk/src/ws-transport.d.ts.map +1 -1
  14. package/dist/{asset-feeds-NG5TKB3V.js → asset-feeds-T35ELX2O.js} +9 -9
  15. package/dist/{asset-feeds-NG5TKB3V.js.map → asset-feeds-T35ELX2O.js.map} +1 -1
  16. package/dist/asset-manager/index.js +11 -6
  17. package/dist/asset-manager/installer.js +5 -5
  18. package/dist/asset-manager/src/index.d.ts.map +1 -1
  19. package/dist/{chunk-BE5KTS2L.js → chunk-2DWXGUZA.js} +2 -2
  20. package/dist/{chunk-BE5KTS2L.js.map → chunk-2DWXGUZA.js.map} +1 -1
  21. package/dist/{chunk-XBG2YDQQ.js → chunk-2ZMO4CFG.js} +3 -3
  22. package/dist/{chunk-XBG2YDQQ.js.map → chunk-2ZMO4CFG.js.map} +1 -1
  23. package/dist/{chunk-X57AMTAH.js → chunk-3CHARYD4.js} +16 -7
  24. package/dist/chunk-3CHARYD4.js.map +1 -0
  25. package/dist/{chunk-LCTRCWBK.js → chunk-6NR2BEIY.js} +4 -4
  26. package/dist/{chunk-LCTRCWBK.js.map → chunk-6NR2BEIY.js.map} +1 -1
  27. package/dist/{chunk-JZPEEMIM.js → chunk-BEO6KN7P.js} +5 -5
  28. package/dist/{chunk-JZPEEMIM.js.map → chunk-BEO6KN7P.js.map} +1 -1
  29. package/dist/{chunk-AAGD2J4H.js → chunk-CBA2XIBF.js} +33 -15
  30. package/dist/chunk-CBA2XIBF.js.map +1 -0
  31. package/dist/{chunk-GWDZW44L.js → chunk-DMG6NJH7.js} +4 -4
  32. package/dist/{chunk-GWDZW44L.js.map → chunk-DMG6NJH7.js.map} +1 -1
  33. package/dist/{chunk-HWTQ6HPO.js → chunk-FDE7XRQA.js} +56 -8
  34. package/dist/chunk-FDE7XRQA.js.map +1 -0
  35. package/dist/{chunk-26YCXWCU.js → chunk-HY33RMEA.js} +3 -3
  36. package/dist/{chunk-26YCXWCU.js.map → chunk-HY33RMEA.js.map} +1 -1
  37. package/dist/chunk-J5TI55E7.js +203 -0
  38. package/dist/chunk-J5TI55E7.js.map +1 -0
  39. package/dist/chunk-JIDKX7GC.js +122 -0
  40. package/dist/chunk-JIDKX7GC.js.map +1 -0
  41. package/dist/{chunk-BDUANIAR.js → chunk-KEQ4GLVM.js} +3 -3
  42. package/dist/{chunk-BDUANIAR.js.map → chunk-KEQ4GLVM.js.map} +1 -1
  43. package/dist/{chunk-DNFIKRO6.js → chunk-KMY7HVQ6.js} +3 -3
  44. package/dist/{chunk-DNFIKRO6.js.map → chunk-KMY7HVQ6.js.map} +1 -1
  45. package/dist/{chunk-B6SSXVF2.js → chunk-MZV6WCF3.js} +81 -49
  46. package/dist/chunk-MZV6WCF3.js.map +1 -0
  47. package/dist/{chunk-DZCK7GRW.js → chunk-P4VHQA4N.js} +22 -6
  48. package/dist/chunk-P4VHQA4N.js.map +1 -0
  49. package/dist/{chunk-OSCJRUKM.js → chunk-RDYOU6N6.js} +2 -2
  50. package/dist/{chunk-OSCJRUKM.js.map → chunk-RDYOU6N6.js.map} +1 -1
  51. package/dist/{chunk-77OXU44H.js → chunk-RSYV7XEN.js} +13 -7
  52. package/dist/chunk-RSYV7XEN.js.map +1 -0
  53. package/dist/{chunk-OUWNTFDG.js → chunk-UQKYT4V6.js} +38 -6
  54. package/dist/chunk-UQKYT4V6.js.map +1 -0
  55. package/dist/chunk-WYGXYGJH.js +688 -0
  56. package/dist/chunk-WYGXYGJH.js.map +1 -0
  57. package/dist/{chunk-TJRWGMD2.js → chunk-ZBZQC5R7.js} +3 -3
  58. package/dist/{chunk-TJRWGMD2.js.map → chunk-ZBZQC5R7.js.map} +1 -1
  59. package/dist/cli/index.js +259 -192
  60. package/dist/cli/index.js.map +1 -1
  61. package/dist/cli/src/commands/catalog.d.ts +18 -0
  62. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  63. package/dist/cli/src/commands/library-cmd.d.ts +2 -2
  64. package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
  65. package/dist/cli/src/commands/library-publish.d.ts +53 -0
  66. package/dist/cli/src/commands/library-publish.d.ts.map +1 -0
  67. package/dist/cli/src/commands/preset-cmd.d.ts +6 -0
  68. package/dist/cli/src/commands/preset-cmd.d.ts.map +1 -1
  69. package/dist/cli/src/commands/preset-export.d.ts +10 -1
  70. package/dist/cli/src/commands/preset-export.d.ts.map +1 -1
  71. package/dist/cli/src/commands/project.d.ts.map +1 -1
  72. package/dist/cli/src/commands/publish-core.d.ts +75 -0
  73. package/dist/cli/src/commands/publish-core.d.ts.map +1 -0
  74. package/dist/cli/src/commands/run.d.ts.map +1 -1
  75. package/dist/cli/src/commands/source-manifest-publish.d.ts +82 -0
  76. package/dist/cli/src/commands/source-manifest-publish.d.ts.map +1 -0
  77. package/dist/cli/src/commands/source-manifest.d.ts +65 -6
  78. package/dist/cli/src/commands/source-manifest.d.ts.map +1 -1
  79. package/dist/cli/src/commands/source.d.ts +13 -0
  80. package/dist/cli/src/commands/source.d.ts.map +1 -1
  81. package/dist/cli/src/commands/store.d.ts.map +1 -1
  82. package/dist/cli/src/driver-error.d.ts +12 -0
  83. package/dist/cli/src/driver-error.d.ts.map +1 -0
  84. package/dist/cli/src/open-library.d.ts +4 -0
  85. package/dist/cli/src/open-library.d.ts.map +1 -1
  86. package/dist/cli/src/store-auth.d.ts +42 -0
  87. package/dist/cli/src/store-auth.d.ts.map +1 -0
  88. package/dist/cli/src/store-client.d.ts +20 -22
  89. package/dist/cli/src/store-client.d.ts.map +1 -1
  90. package/dist/cli/src/store-publisher.d.ts +91 -0
  91. package/dist/cli/src/store-publisher.d.ts.map +1 -0
  92. package/dist/connectors/config.js +5 -5
  93. package/dist/connectors/index.js +6 -6
  94. package/dist/core/index.js +4 -4
  95. package/dist/core/publish-manifest.js +1 -1
  96. package/dist/core/runtime-assets.js +3 -3
  97. package/dist/core/src/cache-paths.d.ts +17 -0
  98. package/dist/core/src/cache-paths.d.ts.map +1 -1
  99. package/dist/core/src/index.d.ts +2 -2
  100. package/dist/core/src/index.d.ts.map +1 -1
  101. package/dist/core/src/publish-manifest.d.ts.map +1 -1
  102. package/dist/core/src/repo-manager.d.ts +13 -2
  103. package/dist/core/src/repo-manager.d.ts.map +1 -1
  104. package/dist/core/src/walker.d.ts +10 -0
  105. package/dist/core/src/walker.d.ts.map +1 -1
  106. package/dist/core/workspace-config.js +2 -2
  107. package/dist/deploy/index.js +4 -4
  108. package/dist/discovery/index.js +2 -2
  109. package/dist/discovery/src/discover-manifest.d.ts.map +1 -1
  110. package/dist/discovery/src/discover.d.ts +17 -4
  111. package/dist/discovery/src/discover.d.ts.map +1 -1
  112. package/dist/discovery/src/index.d.ts +1 -1
  113. package/dist/discovery/src/index.d.ts.map +1 -1
  114. package/dist/discovery/src/reference-lint.d.ts +7 -0
  115. package/dist/discovery/src/reference-lint.d.ts.map +1 -1
  116. package/dist/discovery/src/source-config.d.ts +28 -0
  117. package/dist/discovery/src/source-config.d.ts.map +1 -1
  118. package/dist/discovery/src/tree-entries.d.ts.map +1 -1
  119. package/dist/{ensure-sources-CHC7X7AJ.js → ensure-sources-QDVFUIUP.js} +14 -9
  120. package/dist/ensure-sources-QDVFUIUP.js.map +1 -0
  121. package/dist/factory-assets/connectors/box.js +6 -6
  122. package/dist/factory-assets/connectors/deploy.js +6 -6
  123. package/dist/factory-assets/connectors/devserver.js +6 -6
  124. package/dist/factory-assets/connectors/flow/adapter.js +6 -6
  125. package/dist/factory-assets/connectors/flow/engine.js +4 -4
  126. package/dist/factory-assets/connectors/flow/run-flow.js +7 -7
  127. package/dist/factory-assets/connectors/flow.js +6 -6
  128. package/dist/factory-assets/connectors/git.js +6 -6
  129. package/dist/factory-assets/connectors/gmail.js +6 -6
  130. package/dist/factory-assets/connectors/googledrive.js +6 -6
  131. package/dist/factory-assets/connectors/local.js +6 -6
  132. package/dist/factory-assets/connectors/mattermost.js +6 -6
  133. package/dist/factory-assets/connectors/memory.js +6 -6
  134. package/dist/factory-assets/connectors/minio.js +6 -6
  135. package/dist/factory-assets/connectors/postgres.js +6 -6
  136. package/dist/factory-assets/connectors/s3.js +6 -6
  137. package/dist/factory-assets/connectors/sharepoint.js +6 -6
  138. package/dist/factory-assets/connectors/sqlite.js +6 -6
  139. package/dist/factory-assets/connectors/static-server.js +6 -6
  140. package/dist/factory-assets/connectors/tunnel.js +6 -6
  141. package/dist/factory-assets/connectors/webdav.js +6 -6
  142. package/dist/factory-assets/connectors/xstate-store.js +6 -6
  143. package/dist/factory-assets/connectors/xstate.js +6 -6
  144. package/dist/{flows-CGOCUNO6.js → flows-MRVXTYWC.js} +3 -3
  145. package/dist/{flows-CGOCUNO6.js.map → flows-MRVXTYWC.js.map} +1 -1
  146. package/dist/{helpers-GWG4CYYC.js → helpers-TF7GCBRQ.js} +14 -9
  147. package/dist/{helpers-GWG4CYYC.js.map → helpers-TF7GCBRQ.js.map} +1 -1
  148. package/dist/library/index.js +6 -6
  149. package/dist/library/install.js +4 -4
  150. package/dist/library/src/index.d.ts +2 -2
  151. package/dist/library/src/index.d.ts.map +1 -1
  152. package/dist/library/src/local/local-catalog-source.d.ts +12 -1
  153. package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
  154. package/dist/library/src/sync/manifest-writeback.d.ts +36 -0
  155. package/dist/library/src/sync/manifest-writeback.d.ts.map +1 -1
  156. package/dist/library-publish-K5IBE44D.js +249 -0
  157. package/dist/library-publish-K5IBE44D.js.map +1 -0
  158. package/dist/{open-library-37PXN6MK.js → open-library-4HMIDK3N.js} +13 -13
  159. package/dist/{open-library-37PXN6MK.js.map → open-library-4HMIDK3N.js.map} +1 -1
  160. package/dist/{paths-UVOHWUPY.js → paths-P3DWFUPS.js} +7 -7
  161. package/dist/{paths-UVOHWUPY.js.map → paths-P3DWFUPS.js.map} +1 -1
  162. package/dist/{plugin-store-EIMVEH3O.js → plugin-store-S7OMGI7N.js} +6 -6
  163. package/dist/{plugin-store-EIMVEH3O.js.map → plugin-store-S7OMGI7N.js.map} +1 -1
  164. package/dist/runner/index.js +8 -8
  165. package/dist/runner/src/agent.d.ts.map +1 -1
  166. package/dist/runner/src/capability-registry.d.ts +21 -2
  167. package/dist/runner/src/capability-registry.d.ts.map +1 -1
  168. package/dist/sdk/asset-manager.js +11 -6
  169. package/dist/sdk/core.js +4 -4
  170. package/dist/sdk/flow.js +4 -4
  171. package/dist/sdk/index.js +8 -8
  172. package/dist/sdk/runner.js +8 -8
  173. package/dist/{setup-DINVR6ZQ.js → setup-2CCS63L6.js} +6 -6
  174. package/dist/{setup-DINVR6ZQ.js.map → setup-2CCS63L6.js.map} +1 -1
  175. package/dist/source-LOAM7IIQ.js +30 -0
  176. package/dist/{source-RXAHIGMD.js.map → source-LOAM7IIQ.js.map} +1 -1
  177. package/dist/source-manifest-publish-TGVZ6KMC.js +228 -0
  178. package/dist/source-manifest-publish-TGVZ6KMC.js.map +1 -0
  179. package/dist/tui/index.js +8 -8
  180. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  181. package/dist/workspace-plugin/adapters/omp.js +3 -3
  182. package/dist/workspace-plugin/index.js +1 -1
  183. package/package.json +1 -1
  184. package/dist/chunk-77OXU44H.js.map +0 -1
  185. package/dist/chunk-AAGD2J4H.js.map +0 -1
  186. package/dist/chunk-B6SSXVF2.js.map +0 -1
  187. package/dist/chunk-BJHZHNKR.js +0 -93
  188. package/dist/chunk-BJHZHNKR.js.map +0 -1
  189. package/dist/chunk-DZCK7GRW.js.map +0 -1
  190. package/dist/chunk-HWTQ6HPO.js.map +0 -1
  191. package/dist/chunk-OUWNTFDG.js.map +0 -1
  192. package/dist/chunk-QM2TT2PJ.js +0 -385
  193. package/dist/chunk-QM2TT2PJ.js.map +0 -1
  194. package/dist/chunk-X57AMTAH.js.map +0 -1
  195. package/dist/ensure-sources-CHC7X7AJ.js.map +0 -1
  196. package/dist/source-RXAHIGMD.js +0 -30
  197. package/dist/store-client-T3F663YG.js +0 -15
  198. package/dist/store-client-T3F663YG.js.map +0 -1
@@ -0,0 +1,203 @@
1
+ import { globalSettingsPath, mapLegacyFields } from './chunk-HY33RMEA.js';
2
+ import { rmSync, existsSync, readFileSync, mkdirSync, writeFileSync, chmodSync } from 'fs';
3
+ import { homedir } from 'os';
4
+ import { join, dirname } from 'path';
5
+
6
+ function trimTrailingSlash(url) {
7
+ return url.replace(/\/+$/, "");
8
+ }
9
+ function loadStoreAuthConfig() {
10
+ const home = process.env.SKAILE_HOME ?? join(homedir(), ".skaile");
11
+ return {
12
+ keycloakUrl: trimTrailingSlash(process.env.SKAILE_KEYCLOAK_URL ?? "https://auth.skaile.ai"),
13
+ realm: process.env.SKAILE_STORE_REALM ?? "skaile-store",
14
+ clientId: process.env.SKAILE_STORE_CLI_CLIENT ?? "skaile-store-cli",
15
+ authFile: process.env.SKAILE_AUTH_FILE ?? join(home, "auth.json")
16
+ };
17
+ }
18
+ function oidc(config) {
19
+ const base = `${config.keycloakUrl}/realms/${config.realm}/protocol/openid-connect`;
20
+ return { deviceAuth: `${base}/auth/device`, token: `${base}/token` };
21
+ }
22
+ var EXPIRY_MARGIN_MS = 3e4;
23
+ function readAuth(config) {
24
+ try {
25
+ const parsed = JSON.parse(readFileSync(config.authFile, "utf-8"));
26
+ if (parsed && typeof parsed.access_token === "string") return parsed;
27
+ return null;
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ function writeAuth(config, auth) {
33
+ mkdirSync(dirname(config.authFile), { recursive: true });
34
+ writeFileSync(config.authFile, JSON.stringify(auth, null, 2), { mode: 384 });
35
+ chmodSync(config.authFile, 384);
36
+ }
37
+ function logout(config) {
38
+ try {
39
+ rmSync(config.authFile);
40
+ } catch {
41
+ }
42
+ }
43
+ function hasStoredAuth(config) {
44
+ return readAuth(config) !== null;
45
+ }
46
+ function tokenToStored(token) {
47
+ return {
48
+ access_token: token.access_token,
49
+ refresh_token: token.refresh_token,
50
+ expires_at: Date.now() + (token.expires_in ?? 300) * 1e3 - EXPIRY_MARGIN_MS
51
+ };
52
+ }
53
+ var defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
54
+ function defaultPrompt(url, userCode) {
55
+ process.stderr.write(
56
+ `
57
+ To sign in, open:
58
+
59
+ ${url}
60
+
61
+ and enter the code: ${userCode}
62
+
63
+ Waiting for approval\u2026
64
+ `
65
+ );
66
+ }
67
+ async function deviceLogin(config, deps = {}) {
68
+ const fetchImpl = deps.fetchImpl ?? fetch;
69
+ const sleep = deps.sleep ?? defaultSleep;
70
+ const onPrompt = deps.onPrompt ?? defaultPrompt;
71
+ const endpoints = oidc(config);
72
+ const deviceRes = await fetchImpl(endpoints.deviceAuth, {
73
+ method: "POST",
74
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
75
+ body: new URLSearchParams({ client_id: config.clientId, scope: "openid profile" })
76
+ });
77
+ if (!deviceRes.ok) {
78
+ throw new Error(
79
+ `Device authorization request failed (${deviceRes.status}): ${await deviceRes.text()}`
80
+ );
81
+ }
82
+ const device = await deviceRes.json();
83
+ onPrompt(device.verification_uri_complete ?? device.verification_uri, device.user_code);
84
+ const intervalMs = (device.interval ?? 5) * 1e3;
85
+ const deadline = Date.now() + device.expires_in * 1e3;
86
+ let waitMs = intervalMs;
87
+ while (Date.now() < deadline) {
88
+ await sleep(waitMs);
89
+ const tokenRes = await fetchImpl(endpoints.token, {
90
+ method: "POST",
91
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
92
+ body: new URLSearchParams({
93
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
94
+ device_code: device.device_code,
95
+ client_id: config.clientId
96
+ })
97
+ });
98
+ const token = await tokenRes.json();
99
+ if (tokenRes.ok) {
100
+ const stored = tokenToStored(token);
101
+ writeAuth(config, stored);
102
+ return stored;
103
+ }
104
+ if (token.error === "authorization_pending") continue;
105
+ if (token.error === "slow_down") {
106
+ waitMs += 5e3;
107
+ continue;
108
+ }
109
+ throw new Error(`Sign-in failed: ${token.error_description ?? token.error ?? "unknown error"}`);
110
+ }
111
+ throw new Error("Sign-in timed out before approval.");
112
+ }
113
+ async function refresh(config, refreshToken, fetchImpl) {
114
+ const res = await fetchImpl(oidc(config).token, {
115
+ method: "POST",
116
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
117
+ body: new URLSearchParams({
118
+ grant_type: "refresh_token",
119
+ refresh_token: refreshToken,
120
+ client_id: config.clientId
121
+ })
122
+ });
123
+ const token = await res.json();
124
+ if (!res.ok) {
125
+ throw new Error(`Token refresh failed: ${token.error_description ?? token.error ?? res.status}`);
126
+ }
127
+ const stored = tokenToStored(token);
128
+ writeAuth(config, stored);
129
+ return stored;
130
+ }
131
+ async function getAccessToken(config, deps = {}) {
132
+ const fetchImpl = deps.fetchImpl ?? fetch;
133
+ const auth = readAuth(config);
134
+ if (!auth) throw new Error("Not signed in. Run `skaile store login` first.");
135
+ if (Date.now() < auth.expires_at) return auth.access_token;
136
+ if (!auth.refresh_token) throw new Error("Session expired. Run `skaile store login` again.");
137
+ try {
138
+ return (await refresh(config, auth.refresh_token, fetchImpl)).access_token;
139
+ } catch {
140
+ throw new Error("Session expired and refresh failed. Run `skaile store login` again.");
141
+ }
142
+ }
143
+
144
+ // cli/src/store-client.ts
145
+ function getStoreConfig() {
146
+ const settingsPath = globalSettingsPath();
147
+ let settings = {};
148
+ if (existsSync(settingsPath)) {
149
+ try {
150
+ settings = mapLegacyFields(JSON.parse(readFileSync(settingsPath, "utf-8")));
151
+ } catch {
152
+ settings = {};
153
+ }
154
+ }
155
+ return {
156
+ url: settings.storeUrl ?? process.env.SKAILE_STORE_URL ?? "https://api.skaile.store",
157
+ jwt: null
158
+ };
159
+ }
160
+ function getStoreToken(deps) {
161
+ return getAccessToken(loadStoreAuthConfig(), deps);
162
+ }
163
+ async function storeFetch(config, path, opts) {
164
+ let url = `${config.url}${path}`;
165
+ if (opts?.params) {
166
+ const sp = new URLSearchParams(opts.params);
167
+ url += `?${sp}`;
168
+ }
169
+ const headers = {
170
+ "Content-Type": "application/json",
171
+ Accept: "application/json",
172
+ ...opts?.headers ?? {}
173
+ };
174
+ if (config.jwt) {
175
+ headers.Authorization = `Bearer ${config.jwt}`;
176
+ }
177
+ const fetchOpts = {
178
+ method: opts?.method ?? "GET",
179
+ headers
180
+ };
181
+ if (opts?.body) {
182
+ fetchOpts.body = JSON.stringify(opts.body);
183
+ }
184
+ const controller = new AbortController();
185
+ const timeout = setTimeout(() => controller.abort(), opts?.timeoutMs ?? 1500);
186
+ try {
187
+ const res = await fetch(url, { ...fetchOpts, signal: controller.signal });
188
+ if (!res.ok) {
189
+ const body = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
190
+ throw new Error(body.error ?? `Store API error: ${res.status}`);
191
+ }
192
+ return res.json();
193
+ } finally {
194
+ clearTimeout(timeout);
195
+ }
196
+ }
197
+ function isStoreAuthenticated() {
198
+ return hasStoredAuth(loadStoreAuthConfig());
199
+ }
200
+
201
+ export { deviceLogin, getStoreConfig, getStoreToken, hasStoredAuth, isStoreAuthenticated, loadStoreAuthConfig, logout, storeFetch };
202
+ //# sourceMappingURL=chunk-J5TI55E7.js.map
203
+ //# sourceMappingURL=chunk-J5TI55E7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/src/store-auth.ts","../cli/src/store-client.ts"],"names":["readFileSync"],"mappings":"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","file":"chunk-J5TI55E7.js","sourcesContent":["/**\n * Keycloak Device Authorization Grant (RFC 8628) for the store CLI: a public\n * device-flow client (`skaile-store-cli`) issues a plain realm JWT the store's\n * `AuthGuard` accepts — a CLI can't use the storefront's confidential browser\n * client. Tokens cache at `~/.skaile/auth.json` (0600, shared with `store/cli`);\n * `getAccessToken` refreshes transparently. All targets are env-overridable.\n *\n * @docLink cli/dev-guide#store-auth\n */\nimport { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\n/** Resolved auth targets — every field has a prod default, all env-overridable. */\nexport interface StoreAuthConfig {\n keycloakUrl: string;\n realm: string;\n clientId: string;\n authFile: string;\n}\n\nfunction trimTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Load the auth config. Defaults target the production store\n * (`auth.skaile.ai`, realm `skaile-store`, public client `skaile-store-cli`);\n * override with `SKAILE_KEYCLOAK_URL` / `SKAILE_STORE_REALM` /\n * `SKAILE_STORE_CLI_CLIENT` / `SKAILE_AUTH_FILE` for dev or a preview deploy.\n */\nexport function loadStoreAuthConfig(): StoreAuthConfig {\n const home = process.env.SKAILE_HOME ?? join(homedir(), \".skaile\");\n return {\n keycloakUrl: trimTrailingSlash(process.env.SKAILE_KEYCLOAK_URL ?? \"https://auth.skaile.ai\"),\n realm: process.env.SKAILE_STORE_REALM ?? \"skaile-store\",\n clientId: process.env.SKAILE_STORE_CLI_CLIENT ?? \"skaile-store-cli\",\n authFile: process.env.SKAILE_AUTH_FILE ?? join(home, \"auth.json\"),\n };\n}\n\n/** Keycloak OIDC endpoints derived from the realm base. */\nfunction oidc(config: StoreAuthConfig): { deviceAuth: string; token: string } {\n const base = `${config.keycloakUrl}/realms/${config.realm}/protocol/openid-connect`;\n return { deviceAuth: `${base}/auth/device`, token: `${base}/token` };\n}\n\nexport interface StoredAuth {\n access_token: string;\n refresh_token?: string;\n /** Epoch ms when the access token expires (with a safety margin already applied). */\n expires_at: number;\n}\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n error?: string;\n error_description?: string;\n}\n\ninterface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete?: string;\n interval?: number;\n expires_in: number;\n}\n\n/** Refresh this many ms before real expiry so an in-flight call never 401s. */\nconst EXPIRY_MARGIN_MS = 30_000;\n\n/** Injectable seams so the poll loop is unit-testable without real time or network. */\nexport interface AuthDeps {\n fetchImpl?: typeof fetch;\n sleep?: (ms: number) => Promise<void>;\n /** Called once with the verification URL + user code (default: write to stderr). */\n onPrompt?: (url: string, userCode: string) => void;\n}\n\nfunction readAuth(config: StoreAuthConfig): StoredAuth | null {\n try {\n const parsed = JSON.parse(readFileSync(config.authFile, \"utf-8\"));\n // Reject a corrupt / hand-edited file rather than treat it as a session.\n if (parsed && typeof parsed.access_token === \"string\") return parsed as StoredAuth;\n return null;\n } catch {\n return null;\n }\n}\n\nfunction writeAuth(config: StoreAuthConfig, auth: StoredAuth): void {\n mkdirSync(dirname(config.authFile), { recursive: true });\n writeFileSync(config.authFile, JSON.stringify(auth, null, 2), { mode: 0o600 });\n chmodSync(config.authFile, 0o600);\n}\n\n/** Remove the cached session (sign out). */\nexport function logout(config: StoreAuthConfig): void {\n try {\n rmSync(config.authFile);\n } catch {\n // already absent — nothing to do\n }\n}\n\n/** True when a cached, well-formed session exists (validity/refresh resolved on use). */\nexport function hasStoredAuth(config: StoreAuthConfig): boolean {\n return readAuth(config) !== null;\n}\n\nfunction tokenToStored(token: TokenResponse): StoredAuth {\n return {\n access_token: token.access_token,\n refresh_token: token.refresh_token,\n expires_at: Date.now() + (token.expires_in ?? 300) * 1000 - EXPIRY_MARGIN_MS,\n };\n}\n\nconst defaultSleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\nfunction defaultPrompt(url: string, userCode: string): void {\n process.stderr.write(\n `\\nTo sign in, open:\\n\\n ${url}\\n\\nand enter the code: ${userCode}\\n\\nWaiting for approval…\\n`,\n );\n}\n\n/**\n * Run the device flow to completion, persisting tokens on success. Prints the\n * verification URL + user code for the operator to approve in a browser.\n */\nexport async function deviceLogin(config: StoreAuthConfig, deps: AuthDeps = {}): Promise<StoredAuth> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? defaultSleep;\n const onPrompt = deps.onPrompt ?? defaultPrompt;\n const endpoints = oidc(config);\n\n const deviceRes = await fetchImpl(endpoints.deviceAuth, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({ client_id: config.clientId, scope: \"openid profile\" }),\n });\n if (!deviceRes.ok) {\n throw new Error(\n `Device authorization request failed (${deviceRes.status}): ${await deviceRes.text()}`,\n );\n }\n const device = (await deviceRes.json()) as DeviceAuthResponse;\n\n onPrompt(device.verification_uri_complete ?? device.verification_uri, device.user_code);\n\n const intervalMs = (device.interval ?? 5) * 1000;\n const deadline = Date.now() + device.expires_in * 1000;\n let waitMs = intervalMs;\n\n while (Date.now() < deadline) {\n await sleep(waitMs);\n const tokenRes = await fetchImpl(endpoints.token, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: device.device_code,\n client_id: config.clientId,\n }),\n });\n const token = (await tokenRes.json()) as TokenResponse;\n if (tokenRes.ok) {\n const stored = tokenToStored(token);\n writeAuth(config, stored);\n return stored;\n }\n // RFC 8628 §3.5 pending / slow-down handling.\n if (token.error === \"authorization_pending\") continue;\n if (token.error === \"slow_down\") {\n waitMs += 5_000;\n continue;\n }\n throw new Error(`Sign-in failed: ${token.error_description ?? token.error ?? \"unknown error\"}`);\n }\n throw new Error(\"Sign-in timed out before approval.\");\n}\n\n/** Exchange a refresh token for a fresh access token; persist on success. */\nasync function refresh(\n config: StoreAuthConfig,\n refreshToken: string,\n fetchImpl: typeof fetch,\n): Promise<StoredAuth> {\n const res = await fetchImpl(oidc(config).token, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: config.clientId,\n }),\n });\n const token = (await res.json()) as TokenResponse;\n if (!res.ok) {\n throw new Error(`Token refresh failed: ${token.error_description ?? token.error ?? res.status}`);\n }\n const stored = tokenToStored(token);\n writeAuth(config, stored);\n return stored;\n}\n\n/**\n * Return a valid access token, refreshing if it is expired (or about to). Throws\n * a clear \"run `skaile store login`\" error when there is no usable session.\n */\nexport async function getAccessToken(\n config: StoreAuthConfig,\n deps: AuthDeps = {},\n): Promise<string> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const auth = readAuth(config);\n if (!auth) throw new Error(\"Not signed in. Run `skaile store login` first.\");\n if (Date.now() < auth.expires_at) return auth.access_token;\n if (!auth.refresh_token) throw new Error(\"Session expired. Run `skaile store login` again.\");\n try {\n return (await refresh(config, auth.refresh_token, fetchImpl)).access_token;\n } catch {\n throw new Error(\"Session expired and refresh failed. Run `skaile store login` again.\");\n }\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { globalSettingsPath, mapLegacyFields } from \"@skaile/workspaces/core\";\nimport { type AuthDeps, getAccessToken, hasStoredAuth, loadStoreAuthConfig } from \"./store-auth.ts\";\n\n/**\n * Connection configuration for the AI Asset Store API. `jwt` is normally left\n * null here and filled per-call by the caller from {@link getStoreToken} (the\n * device-flow session); it stays on the type for the `{ ...config, jwt }` spread.\n *\n * @docLink cli/dev-guide#store-client\n */\nexport interface StoreConfig {\n url: string;\n jwt: string | null;\n}\n\n/**\n * Read the store API base URL (settings `storeUrl` → `SKAILE_STORE_URL` →\n * default). Auth is not read here — it lives in the device-flow session; see\n * {@link getStoreToken}.\n *\n * @docLink cli/dev-guide#store-client\n */\nexport function getStoreConfig(): StoreConfig {\n const settingsPath = globalSettingsPath();\n let settings: Record<string, any> = {};\n if (existsSync(settingsPath)) {\n try {\n settings = mapLegacyFields(JSON.parse(readFileSync(settingsPath, \"utf-8\")));\n } catch {\n settings = {};\n }\n }\n return {\n url: settings.storeUrl ?? process.env.SKAILE_STORE_URL ?? \"https://api.skaile.store\",\n jwt: null,\n };\n}\n\n/**\n * Return a valid store access token (Keycloak device-flow session, refreshed if\n * needed). Throws a \"run `skaile store login`\" error when there is no session.\n * This is the auth source for every `/api/v1/*` publisher call.\n */\nexport function getStoreToken(deps?: AuthDeps): Promise<string> {\n return getAccessToken(loadStoreAuthConfig(), deps);\n}\n\n/**\n * Make an authenticated HTTP request to the store REST API.\n *\n * @param config - Store connection config (URL + auth token).\n * @param path - API path (e.g. `/api/assets`).\n * @param opts - Optional method, body, query params, extra headers, and\n * `timeoutMs` (default 1500). Publisher calls pass a longer timeout because\n * they trigger server-side clone/sync work.\n * @returns Parsed JSON response body.\n * @docLink cli/dev-guide#store-client\n */\nexport async function storeFetch<T = any>(\n config: StoreConfig,\n path: string,\n opts?: {\n method?: string;\n body?: unknown;\n params?: Record<string, string>;\n headers?: Record<string, string>;\n timeoutMs?: number;\n },\n): Promise<T> {\n let url = `${config.url}${path}`;\n if (opts?.params) {\n const sp = new URLSearchParams(opts.params);\n url += `?${sp}`;\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...(opts?.headers ?? {}),\n };\n if (config.jwt) {\n headers.Authorization = `Bearer ${config.jwt}`;\n }\n\n const fetchOpts: RequestInit = {\n method: opts?.method ?? \"GET\",\n headers,\n };\n if (opts?.body) {\n fetchOpts.body = JSON.stringify(opts.body);\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), opts?.timeoutMs ?? 1_500);\n try {\n const res = await fetch(url, { ...fetchOpts, signal: controller.signal });\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));\n throw new Error((body as any).error ?? `Store API error: ${res.status}`);\n }\n return res.json() as Promise<T>;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Return `true` when a store session exists (a Keycloak device-flow token cached\n * at `~/.skaile/auth.json`). Validity/refresh is resolved on use via\n * {@link getStoreToken}.\n *\n * @docLink cli/dev-guide#store-client\n */\nexport function isStoreAuthenticated(): boolean {\n return hasStoredAuth(loadStoreAuthConfig());\n}\n"]}
@@ -0,0 +1,122 @@
1
+ import { getStoreConfig, getStoreToken, storeFetch } from './chunk-J5TI55E7.js';
2
+ import { logErr, logWarn, logOk, logInfo } from './chunk-KMY7HVQ6.js';
3
+
4
+ // cli/src/store-publisher.ts
5
+ function makeHttpPublisherClient(config = getStoreConfig(), timeoutMs = 2e4) {
6
+ const call = async (path, opts) => {
7
+ const jwt = await getStoreToken();
8
+ return storeFetch({ ...config, jwt }, path, { timeoutMs, ...opts });
9
+ };
10
+ return {
11
+ me: () => call("/api/v1/me"),
12
+ sourcesAdd: (body) => call("/api/v1/sources", { method: "POST", body }),
13
+ sourcesList: () => call("/api/v1/sources"),
14
+ sourceSync: (id) => call(`/api/v1/sources/${id}/sync`, { method: "POST", body: {} }),
15
+ jobGet: (jobId) => call(`/api/v1/jobs/${jobId}`),
16
+ sourceCandidates: (id) => call(`/api/v1/sources/${id}/candidates`),
17
+ assetPreview: (id) => call(`/api/v1/assets/${id}/preview`),
18
+ assetPublish: (id, body, dryRun) => call(`/api/v1/assets/${id}/publish`, {
19
+ method: "POST",
20
+ body,
21
+ ...dryRun ? { params: { dryRun: "1" } } : {}
22
+ }),
23
+ assetUnpublish: (id) => call(`/api/v1/assets/${id}/unpublish`, { method: "POST", body: {} })
24
+ };
25
+ }
26
+
27
+ // cli/src/commands/publish-core.ts
28
+ function matchCandidatesToManifest(candidates, manifest) {
29
+ const wanted = new Set((manifest.assets ?? []).map((a) => `${a.kind}:${a.name}`));
30
+ return candidates.filter((c) => wanted.has(`${c.kind}:${c.name}`));
31
+ }
32
+ function refFor(kind, publisher, name, version) {
33
+ const base = `${kind}:@${publisher}/${name}`;
34
+ return version ? `${base}#${version}` : base;
35
+ }
36
+ function bareName(ref) {
37
+ const afterKind = ref.includes(":") ? ref.slice(ref.indexOf(":") + 1) : ref;
38
+ const afterScope = afterKind.includes("/") ? afterKind.slice(afterKind.indexOf("/") + 1) : afterKind;
39
+ return afterScope.split("#")[0];
40
+ }
41
+ async function pollJob(client, jobId, intervalMs = 1500, timeoutMs = 6e4) {
42
+ const deadline = Date.now() + timeoutMs;
43
+ let job = await client.jobGet(jobId);
44
+ while (job.status === "running" && Date.now() < deadline) {
45
+ await new Promise((r) => setTimeout(r, intervalMs));
46
+ job = await client.jobGet(jobId);
47
+ }
48
+ return job;
49
+ }
50
+ function isDupSourceError(err) {
51
+ const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
52
+ return /\b409\b|conflict|duplicate|already exists|already registered|unique/.test(msg);
53
+ }
54
+ async function publishToStore(opts) {
55
+ const { sourceUrl, ref, sidecar, manifest, assetName, client: pub } = opts;
56
+ let sourceId;
57
+ try {
58
+ const added = await pub.sourcesAdd({
59
+ url: sourceUrl,
60
+ ref,
61
+ ...sidecar ? { sidecarUrl: sidecar.url, sidecarRef: sidecar.ref } : {}
62
+ });
63
+ sourceId = added.id;
64
+ } catch (err) {
65
+ if (!isDupSourceError(err)) throw err;
66
+ const rows = await pub.sourcesList();
67
+ const found = rows.find((r) => r.url === sourceUrl);
68
+ if (!found) {
69
+ throw new Error(
70
+ `Source ${sourceUrl} looked already-registered but no owned row matched: ${err instanceof Error ? err.message : String(err)}`
71
+ );
72
+ }
73
+ sourceId = found.id;
74
+ }
75
+ const { jobId } = await pub.sourceSync(sourceId);
76
+ const job = await pollJob(pub, jobId);
77
+ if (job.status === "failed" || job.status === "cancelled") {
78
+ const failed = (job.items ?? []).filter((i) => i.status === "failed");
79
+ for (const i of failed) logErr(`sync: ${i.label}: ${i.error ?? "failed"}`);
80
+ logErr(`Source sync ${job.status}.`);
81
+ process.exit(1);
82
+ }
83
+ if (job.status === "running") {
84
+ logErr("Source sync timed out before completing \u2014 re-run `publish`, or check the store.");
85
+ process.exit(1);
86
+ }
87
+ let candidates = matchCandidatesToManifest(await pub.sourceCandidates(sourceId), manifest);
88
+ if (assetName) candidates = candidates.filter((c) => c.name === assetName);
89
+ if (candidates.length === 0) {
90
+ logWarn("No candidates discovered \u2014 check the manifest and the source ref.");
91
+ process.exit(1);
92
+ }
93
+ const published = [];
94
+ for (const c of candidates) {
95
+ try {
96
+ const preview = await pub.assetPreview(c.id);
97
+ const res = await pub.assetPublish(c.id, { ref, files: preview.discoveredFiles });
98
+ if (res.jobId) {
99
+ const pubJob = await pollJob(pub, res.jobId);
100
+ if (pubJob.status !== "succeeded") {
101
+ const errs = (pubJob.items ?? []).filter((i) => i.status === "failed").map((i) => i.error).filter(Boolean);
102
+ logWarn(
103
+ `Publish of ${c.kind}:${c.name} did not succeed (${pubJob.status})` + (errs.length ? `: ${errs.join("; ")}` : "")
104
+ );
105
+ continue;
106
+ }
107
+ }
108
+ published.push(refFor(c.kind, preview.candidate.publisherNamespace, c.name, c.version));
109
+ } catch (err) {
110
+ logWarn(
111
+ `Failed to publish ${c.kind}:${c.name}: ${err instanceof Error ? err.message : String(err)}`
112
+ );
113
+ }
114
+ }
115
+ logOk(`Published ${published.length} asset(s):`);
116
+ for (const r of published) logInfo(` ${r}`);
117
+ return { published };
118
+ }
119
+
120
+ export { bareName, makeHttpPublisherClient, publishToStore, refFor };
121
+ //# sourceMappingURL=chunk-JIDKX7GC.js.map
122
+ //# sourceMappingURL=chunk-JIDKX7GC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/src/store-publisher.ts","../cli/src/commands/publish-core.ts"],"names":[],"mappings":"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","file":"chunk-JIDKX7GC.js","sourcesContent":["/**\n * Typed REST client for the AI Asset Store **publisher** surface — the\n * curator-publish flow (`skaile source manifest publish` / `yank`). Thin\n * wrappers over {@link storeFetch}; every method maps 1:1 to an `/api/v1/…`\n * endpoint. The {@link PublisherClient} interface is injectable so the\n * orchestration in `commands/source-manifest-publish.ts` can be unit-tested\n * against a fake without a live store.\n *\n * @docLink cli/dev-guide#store-publisher\n */\n\nimport { getStoreConfig, getStoreToken, type StoreConfig, storeFetch } from \"./store-client.ts\";\n\n/**\n * The publisher REST surface used by the curator-publish flow. Kept minimal —\n * only the endpoints `runPublish` / `runYank` actually call. Response shapes\n * are narrowed to the fields the orchestration reads (the server returns more).\n */\nexport interface PublisherClient {\n /** Identity of the caller; `username` is the publisher namespace. */\n me(): Promise<{ username: string }>;\n /** Register (or re-register) a source; returns the created/existing row id. */\n sourcesAdd(body: {\n url: string;\n ref: string;\n sidecarUrl?: string;\n sidecarRef?: string;\n }): Promise<{ id: string }>;\n /** List sources — used to recover an id when `sourcesAdd` rejects a dup url. */\n sourcesList(): Promise<Array<{ id: string; url: string }>>;\n /** Kick off a source sync; returns the async job id to poll. */\n sourceSync(id: string): Promise<{ jobId: string }>;\n /** Poll a job's terminal status + per-item results. */\n jobGet(\n jobId: string,\n ): Promise<{ status: string; items?: Array<{ label: string; status: string; error?: string }> }>;\n /** Discovered publishable candidates for a synced source. */\n sourceCandidates(id: string): Promise<\n Array<{\n id: string;\n name: string;\n version: string;\n kind: string;\n published: boolean;\n assetRoot: string;\n }>\n >;\n /** Per-asset preview — the discovered file set + resolved candidate metadata. */\n assetPreview(id: string): Promise<{\n discoveredFiles: string[];\n candidate: { name: string; version: string; kind: string; publisherNamespace: string };\n }>;\n /**\n * Publish one asset. `dryRun` returns the would-be `{ manifest }` without\n * launching a job; the normal path returns `{ jobId }`.\n */\n assetPublish(\n id: string,\n body: { ref: string; files: string[] },\n dryRun?: boolean,\n ): Promise<{ jobId?: string; manifest?: unknown }>;\n /** Retract a published asset. Response body is ignored. */\n assetUnpublish(id: string): Promise<unknown>;\n}\n\n/**\n * Construct the real HTTP-backed {@link PublisherClient}. Every call carries a\n * longer timeout than the default store client because publish/sync trigger\n * server-side clone work.\n *\n * @param config - Store connection config; defaults to {@link getStoreConfig}.\n * @param timeoutMs - Per-request abort timeout (default 20s).\n */\nexport function makeHttpPublisherClient(\n config: StoreConfig = getStoreConfig(),\n timeoutMs = 20_000,\n): PublisherClient {\n // Acquire a fresh Keycloak token per call (device-flow session in\n // ~/.skaile/auth.json, refreshed on demand) rather than a static config.jwt.\n const call = async <T>(\n path: string,\n opts?: { method?: string; body?: unknown; params?: Record<string, string> },\n ): Promise<T> => {\n const jwt = await getStoreToken();\n return storeFetch<T>({ ...config, jwt }, path, { timeoutMs, ...opts });\n };\n return {\n me: () => call(\"/api/v1/me\"),\n sourcesAdd: (body) => call(\"/api/v1/sources\", { method: \"POST\", body }),\n sourcesList: () => call(\"/api/v1/sources\"),\n sourceSync: (id) => call(`/api/v1/sources/${id}/sync`, { method: \"POST\", body: {} }),\n jobGet: (jobId) => call(`/api/v1/jobs/${jobId}`),\n sourceCandidates: (id) => call(`/api/v1/sources/${id}/candidates`),\n assetPreview: (id) => call(`/api/v1/assets/${id}/preview`),\n assetPublish: (id, body, dryRun) =>\n call(`/api/v1/assets/${id}/publish`, {\n method: \"POST\",\n body,\n ...(dryRun ? { params: { dryRun: \"1\" } } : {}),\n }),\n assetUnpublish: (id) => call(`/api/v1/assets/${id}/unpublish`, { method: \"POST\", body: {} }),\n };\n}\n","/**\n * Shared store-interaction core for the two publish front-ends — the curator\n * sidecar flow (`source manifest publish`) and the first-party library flow\n * (`library publish`). Both differ only in their git side-effects + how they\n * resolve the source repo; the store orchestration below (register → sync →\n * candidates → per-asset preview+publish) is identical.\n *\n * The store REST surface is reached through the injectable {@link PublisherClient}\n * so the orchestration stays unit/integration-testable without a live store.\n *\n * @docLink cli/commands/source#manifest-publish\n */\n\nimport type { SkPublishManifest } from \"@skaile/workspaces/core\";\nimport { logErr, logInfo, logOk, logWarn } from \"../helpers.ts\";\nimport type { PublisherClient } from \"../store-publisher.ts\";\n\n/** One candidate row shape the matcher operates on (kind + name are the key). */\ninterface CandidateLike {\n kind: string;\n name: string;\n}\n\n/**\n * Keep only candidates whose `(kind, name)` pair is declared in the manifest.\n * The backend may merge extra assets from the base repo into the candidate\n * list; a publish only touches what the manifest curated/declared.\n */\nexport function matchCandidatesToManifest<T extends CandidateLike>(\n candidates: T[],\n manifest: SkPublishManifest,\n): T[] {\n const wanted = new Set((manifest.assets ?? []).map((a) => `${a.kind}:${a.name}`));\n return candidates.filter((c) => wanted.has(`${c.kind}:${c.name}`));\n}\n\n/** A canonical ref string `kind:@publisher/name[#version]` for reporting. */\nexport function refFor(kind: string, publisher: string, name: string, version?: string): string {\n const base = `${kind}:@${publisher}/${name}`;\n return version ? `${base}#${version}` : base;\n}\n\n/** The bare asset name from a `kind:@publisher/name#version` ref or a plain name. */\nexport function bareName(ref: string): string {\n const afterKind = ref.includes(\":\") ? ref.slice(ref.indexOf(\":\") + 1) : ref;\n const afterScope = afterKind.includes(\"/\") ? afterKind.slice(afterKind.indexOf(\"/\") + 1) : afterKind;\n return afterScope.split(\"#\")[0];\n}\n\n/**\n * Poll a job until it leaves `running` or the deadline passes. Returns the last\n * observed state — the caller MUST treat a still-`running` result as a timeout\n * (not success), since it means the deadline was hit before the job finished.\n */\nexport async function pollJob(\n client: PublisherClient,\n jobId: string,\n intervalMs = 1_500,\n timeoutMs = 60_000,\n): Promise<{ status: string; items?: Array<{ label: string; status: string; error?: string }> }> {\n const deadline = Date.now() + timeoutMs;\n let job = await client.jobGet(jobId);\n while (job.status === \"running\" && Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, intervalMs));\n job = await client.jobGet(jobId);\n }\n return job;\n}\n\n/**\n * True when a `sourcesAdd` rejection is a duplicate-URL conflict (the source is\n * already registered) — the only error the publish flow recovers from by looking\n * the existing row up. Every other failure (auth, 5xx, network) must propagate.\n */\nexport function isDupSourceError(err: unknown): boolean {\n const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();\n return /\\b409\\b|conflict|duplicate|already exists|already registered|unique/.test(msg);\n}\n\n/**\n * Register + sync the source, then publish its curated/declared candidates —\n * the store-side steps shared by both publish front-ends. Git side-effects (the\n * sidecar push, or the library commit+push) happen in the caller *before* this;\n * this function is purely store interaction.\n *\n * The sidecar front-end passes `sidecar` (so `sourcesAdd` carries the sidecar\n * pin); the library front-end omits it (the source repo IS the manifest host).\n * `assetName`, when set, narrows publication to the single candidate of that\n * name. Fatal store states (`sourcesAdd` non-dup failure) surface; sync failures\n * and empty candidate sets `process.exit(1)` with the same messages as before.\n */\nexport async function publishToStore(opts: {\n sourceUrl: string;\n ref: string;\n sidecar?: { url: string; ref: string };\n manifest: SkPublishManifest;\n assetName?: string;\n client: PublisherClient;\n}): Promise<{ published: string[] }> {\n const { sourceUrl, ref, sidecar, manifest, assetName, client: pub } = opts;\n\n let sourceId: string;\n try {\n const added = await pub.sourcesAdd({\n url: sourceUrl,\n ref,\n ...(sidecar ? { sidecarUrl: sidecar.url, sidecarRef: sidecar.ref } : {}),\n });\n sourceId = added.id;\n } catch (err) {\n // Only a duplicate-url conflict is recoverable (source already registered);\n // auth/5xx/network failures must surface, not silently reuse a stale row.\n if (!isDupSourceError(err)) throw err;\n const rows = await pub.sourcesList();\n const found = rows.find((r) => r.url === sourceUrl);\n if (!found) {\n throw new Error(\n `Source ${sourceUrl} looked already-registered but no owned row matched: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n sourceId = found.id;\n }\n\n const { jobId } = await pub.sourceSync(sourceId);\n const job = await pollJob(pub, jobId);\n if (job.status === \"failed\" || job.status === \"cancelled\") {\n const failed = (job.items ?? []).filter((i) => i.status === \"failed\");\n for (const i of failed) logErr(`sync: ${i.label}: ${i.error ?? \"failed\"}`);\n logErr(`Source sync ${job.status}.`);\n process.exit(1);\n }\n // A still-`running` job means the poll deadline was hit — do NOT proceed on an\n // unfinished sync (it would read incomplete candidates).\n if (job.status === \"running\") {\n logErr(\"Source sync timed out before completing — re-run `publish`, or check the store.\");\n process.exit(1);\n }\n\n let candidates = matchCandidatesToManifest(await pub.sourceCandidates(sourceId), manifest);\n if (assetName) candidates = candidates.filter((c) => c.name === assetName);\n if (candidates.length === 0) {\n logWarn(\"No candidates discovered — check the manifest and the source ref.\");\n process.exit(1);\n }\n\n const published: string[] = [];\n for (const c of candidates) {\n try {\n const preview = await pub.assetPreview(c.id);\n const res = await pub.assetPublish(c.id, { ref, files: preview.discoveredFiles });\n // Publish is async — wait for the job so we only report refs that actually\n // landed, not ones whose import is still in flight or about to fail.\n if (res.jobId) {\n const pubJob = await pollJob(pub, res.jobId);\n if (pubJob.status !== \"succeeded\") {\n const errs = (pubJob.items ?? [])\n .filter((i) => i.status === \"failed\")\n .map((i) => i.error)\n .filter(Boolean);\n logWarn(\n `Publish of ${c.kind}:${c.name} did not succeed (${pubJob.status})` +\n (errs.length ? `: ${errs.join(\"; \")}` : \"\"),\n );\n continue;\n }\n }\n published.push(refFor(c.kind, preview.candidate.publisherNamespace, c.name, c.version));\n } catch (err) {\n logWarn(\n `Failed to publish ${c.kind}:${c.name}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n logOk(`Published ${published.length} asset(s):`);\n for (const r of published) logInfo(` ${r}`);\n return { published };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { resolveSkWorkspaceConfig } from './chunk-OUWNTFDG.js';
1
+ import { resolveSkWorkspaceConfig } from './chunk-UQKYT4V6.js';
2
2
  import { parseFrontmatter } from './chunk-BQCGFPHW.js';
3
3
  import { createLogger } from './chunk-JB35MVBN.js';
4
4
  import { readFileSync, existsSync, readdirSync, statSync } from 'fs';
@@ -388,5 +388,5 @@ function resolveAuthRef(auth, mountId) {
388
388
  }
389
389
 
390
390
  export { EnvSecretProvider, ForgeSecretProvider, InMemorySecretProvider, LegacyAuthGrammarError, LockedSecretProvider, OAuthRequiredError, PreMintedSecretProvider, SecretProviderChain, createCliSecretProviderChain, createForgeSecretProviderChain, deriveSingleMaterializedConnectorDeclaration, fromMaterializedConnectorMd, loadConnectorDeclarations, loadMaterializedConnectorDeclarations, resolveAuthRef, resolveBackendAuthFor };
391
- //# sourceMappingURL=chunk-BDUANIAR.js.map
392
- //# sourceMappingURL=chunk-BDUANIAR.js.map
391
+ //# sourceMappingURL=chunk-KEQ4GLVM.js.map
392
+ //# sourceMappingURL=chunk-KEQ4GLVM.js.map