@gadgetinc/ggt 0.3.3 → 0.4.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 (148) hide show
  1. package/README.md +139 -76
  2. package/bin/dev.js +4 -7
  3. package/lib/__generated__/graphql.js.map +1 -1
  4. package/lib/commands/deploy.js +227 -0
  5. package/lib/commands/deploy.js.map +1 -0
  6. package/lib/commands/list.js +20 -16
  7. package/lib/commands/list.js.map +1 -1
  8. package/lib/commands/login.js +22 -20
  9. package/lib/commands/login.js.map +1 -1
  10. package/lib/commands/logout.js +13 -9
  11. package/lib/commands/logout.js.map +1 -1
  12. package/lib/commands/root.js +89 -56
  13. package/lib/commands/root.js.map +1 -1
  14. package/lib/commands/sync.js +253 -496
  15. package/lib/commands/sync.js.map +1 -1
  16. package/lib/commands/version.js +21 -0
  17. package/lib/commands/version.js.map +1 -0
  18. package/lib/commands/whoami.js +15 -11
  19. package/lib/commands/whoami.js.map +1 -1
  20. package/lib/main.js +4 -10
  21. package/lib/main.js.map +1 -1
  22. package/lib/services/{app.js → app/app.js} +8 -3
  23. package/lib/services/app/app.js.map +1 -0
  24. package/lib/services/app/arg.js +28 -0
  25. package/lib/services/app/arg.js.map +1 -0
  26. package/lib/services/app/edit-graphql.js +389 -0
  27. package/lib/services/app/edit-graphql.js.map +1 -0
  28. package/lib/services/command/arg.js +53 -0
  29. package/lib/services/command/arg.js.map +1 -0
  30. package/lib/services/command/command.js +27 -0
  31. package/lib/services/command/command.js.map +1 -0
  32. package/lib/services/command/context.js +60 -0
  33. package/lib/services/command/context.js.map +1 -0
  34. package/lib/services/{config.js → config/config.js} +29 -31
  35. package/lib/services/config/config.js.map +1 -0
  36. package/lib/services/config/env.js +22 -0
  37. package/lib/services/config/env.js.map +1 -0
  38. package/lib/services/config/package-json.js +9 -0
  39. package/lib/services/config/package-json.js.map +1 -0
  40. package/lib/services/filesync/changes.js +97 -0
  41. package/lib/services/filesync/changes.js.map +1 -0
  42. package/lib/services/filesync/conflicts.js +137 -0
  43. package/lib/services/filesync/conflicts.js.map +1 -0
  44. package/lib/services/filesync/directory.js +253 -0
  45. package/lib/services/filesync/directory.js.map +1 -0
  46. package/lib/services/filesync/error.js +67 -0
  47. package/lib/services/filesync/error.js.map +1 -0
  48. package/lib/services/filesync/file.js +3 -0
  49. package/lib/services/filesync/file.js.map +1 -0
  50. package/lib/services/filesync/filesync.js +675 -0
  51. package/lib/services/filesync/filesync.js.map +1 -0
  52. package/lib/services/filesync/hashes.js +150 -0
  53. package/lib/services/filesync/hashes.js.map +1 -0
  54. package/lib/services/http/auth.js +41 -0
  55. package/lib/services/http/auth.js.map +1 -0
  56. package/lib/services/http/http.js +64 -0
  57. package/lib/services/http/http.js.map +1 -0
  58. package/lib/services/output/log/field.js +3 -0
  59. package/lib/services/output/log/field.js.map +1 -0
  60. package/lib/services/output/log/format/format.js +8 -0
  61. package/lib/services/output/log/format/format.js.map +1 -0
  62. package/lib/services/output/log/format/json.js +45 -0
  63. package/lib/services/output/log/format/json.js.map +1 -0
  64. package/lib/services/output/log/format/pretty.js +147 -0
  65. package/lib/services/output/log/format/pretty.js.map +1 -0
  66. package/lib/services/output/log/level.js +41 -0
  67. package/lib/services/output/log/level.js.map +1 -0
  68. package/lib/services/output/log/logger.js +40 -0
  69. package/lib/services/output/log/logger.js.map +1 -0
  70. package/lib/services/output/log/printer.js +120 -0
  71. package/lib/services/output/log/printer.js.map +1 -0
  72. package/lib/services/output/log/structured.js +52 -0
  73. package/lib/services/output/log/structured.js.map +1 -0
  74. package/lib/services/{notify.js → output/notify.js} +7 -6
  75. package/lib/services/output/notify.js.map +1 -0
  76. package/lib/services/output/prompt.js +52 -0
  77. package/lib/services/output/prompt.js.map +1 -0
  78. package/lib/services/output/report.js +162 -0
  79. package/lib/services/output/report.js.map +1 -0
  80. package/lib/services/output/sprint.js +21 -0
  81. package/lib/services/output/sprint.js.map +1 -0
  82. package/lib/services/output/stream.js +54 -0
  83. package/lib/services/output/stream.js.map +1 -0
  84. package/lib/services/{version.js → output/update.js} +24 -16
  85. package/lib/services/output/update.js.map +1 -0
  86. package/lib/services/user/session.js +50 -0
  87. package/lib/services/user/session.js.map +1 -0
  88. package/lib/services/{user.js → user/user.js} +23 -14
  89. package/lib/services/user/user.js.map +1 -0
  90. package/lib/services/util/boolean.js +15 -0
  91. package/lib/services/util/boolean.js.map +1 -0
  92. package/lib/services/util/collection.js +38 -0
  93. package/lib/services/util/collection.js.map +1 -0
  94. package/lib/services/util/function.js +97 -0
  95. package/lib/services/util/function.js.map +1 -0
  96. package/lib/services/{is.js → util/is.js} +7 -0
  97. package/lib/services/util/is.js.map +1 -0
  98. package/lib/services/util/number.js +27 -0
  99. package/lib/services/util/number.js.map +1 -0
  100. package/lib/services/util/object.js +101 -0
  101. package/lib/services/util/object.js.map +1 -0
  102. package/lib/services/util/paths.js +36 -0
  103. package/lib/services/util/paths.js.map +1 -0
  104. package/lib/services/{promise.js → util/promise.js} +5 -7
  105. package/lib/services/util/promise.js.map +1 -0
  106. package/npm-shrinkwrap.json +2143 -1304
  107. package/package.json +50 -42
  108. package/lib/commands/index.js +0 -9
  109. package/lib/commands/index.js.map +0 -1
  110. package/lib/services/app.js.map +0 -1
  111. package/lib/services/args.js +0 -28
  112. package/lib/services/args.js.map +0 -1
  113. package/lib/services/collections.js +0 -17
  114. package/lib/services/collections.js.map +0 -1
  115. package/lib/services/config.js.map +0 -1
  116. package/lib/services/debounce.js +0 -21
  117. package/lib/services/debounce.js.map +0 -1
  118. package/lib/services/defaults.js +0 -8
  119. package/lib/services/defaults.js.map +0 -1
  120. package/lib/services/edit-graphql.js +0 -202
  121. package/lib/services/edit-graphql.js.map +0 -1
  122. package/lib/services/errors.js +0 -277
  123. package/lib/services/errors.js.map +0 -1
  124. package/lib/services/filesync.js +0 -404
  125. package/lib/services/filesync.js.map +0 -1
  126. package/lib/services/fs.js +0 -35
  127. package/lib/services/fs.js.map +0 -1
  128. package/lib/services/http.js +0 -53
  129. package/lib/services/http.js.map +0 -1
  130. package/lib/services/is.js.map +0 -1
  131. package/lib/services/log.js +0 -45
  132. package/lib/services/log.js.map +0 -1
  133. package/lib/services/noop.js +0 -4
  134. package/lib/services/noop.js.map +0 -1
  135. package/lib/services/notify.js.map +0 -1
  136. package/lib/services/output.js +0 -74
  137. package/lib/services/output.js.map +0 -1
  138. package/lib/services/promise.js.map +0 -1
  139. package/lib/services/prompt.js +0 -22
  140. package/lib/services/prompt.js.map +0 -1
  141. package/lib/services/session.js +0 -31
  142. package/lib/services/session.js.map +0 -1
  143. package/lib/services/sleep.js +0 -21
  144. package/lib/services/sleep.js.map +0 -1
  145. package/lib/services/timeout.js +0 -8
  146. package/lib/services/timeout.js.map +0 -1
  147. package/lib/services/user.js.map +0 -1
  148. package/lib/services/version.js.map +0 -1
@@ -0,0 +1,389 @@
1
+ import { _ as _define_property } from "@swc/helpers/_/_define_property";
2
+ import { createClient } from "graphql-ws";
3
+ import assert from "node:assert";
4
+ import PQueue from "p-queue";
5
+ import pluralize from "pluralize";
6
+ import WebSocket from "ws";
7
+ import { config } from "../config/config.js";
8
+ import { loadCookie } from "../http/auth.js";
9
+ import { http } from "../http/http.js";
10
+ import { createLogger } from "../output/log/logger.js";
11
+ import { CLIError, IsBug } from "../output/report.js";
12
+ import { sprint } from "../output/sprint.js";
13
+ import { uniq } from "../util/collection.js";
14
+ import { noop, unthunk } from "../util/function.js";
15
+ import { isCloseEvent, isError, isErrorEvent, isGraphQLErrors, isObject, isString } from "../util/is.js";
16
+ import { serializeError } from "../util/object.js";
17
+ var ConnectionStatus;
18
+ (function(ConnectionStatus) {
19
+ ConnectionStatus[ConnectionStatus["CONNECTED"] = 0] = "CONNECTED";
20
+ ConnectionStatus[ConnectionStatus["DISCONNECTED"] = 1] = "DISCONNECTED";
21
+ ConnectionStatus[ConnectionStatus["RECONNECTING"] = 2] = "RECONNECTING";
22
+ })(ConnectionStatus || (ConnectionStatus = {}));
23
+ const log = createLogger({
24
+ name: "edit-graphql"
25
+ });
26
+ /**
27
+ * EditGraphQL is a GraphQL client connected to a Gadget application's
28
+ * /edit/api/graphql-ws endpoint.
29
+ */ export class EditGraphQL {
30
+ /**
31
+ * Subscribe to a GraphQL query.
32
+ *
33
+ * This method is typically used to subscribe to a GraphQL
34
+ * subscription. If you want to execute a GraphQL query or mutation,
35
+ * use {@link EditGraphQL.query} instead.
36
+ *
37
+ * @param payload The query and variables to send to the server.
38
+ * @param sink The callbacks to invoke when the server responds.
39
+ * @returns A function to unsubscribe from the subscription.
40
+ */ subscribe({ onData, ...options }) {
41
+ const unsubscribe = this._subscribe({
42
+ ...options,
43
+ onResult: async (result)=>{
44
+ if (result.errors) {
45
+ unsubscribe();
46
+ await options.onError(new EditGraphQLError(options.query, result.errors));
47
+ return;
48
+ }
49
+ if (!result.data) {
50
+ unsubscribe();
51
+ await options.onError(new EditGraphQLError(options.query, "Received a GraphQL response without errors or data"));
52
+ return;
53
+ }
54
+ await onData(result.data);
55
+ }
56
+ });
57
+ return unsubscribe;
58
+ }
59
+ /**
60
+ * Execute a GraphQL query or mutation.
61
+ *
62
+ * @param payload The query and variables to send to the server.
63
+ * @returns The data returned by the server.
64
+ */ async query({ query, variables }) {
65
+ const result = await this._query({
66
+ query,
67
+ variables
68
+ });
69
+ if (result.errors) {
70
+ throw new EditGraphQLError(query, result.errors);
71
+ }
72
+ if (!result.data) {
73
+ throw new EditGraphQLError(query, "We received a response without data");
74
+ }
75
+ return result.data;
76
+ }
77
+ /**
78
+ * Close the connection to the server.
79
+ */ async dispose() {
80
+ await this._client.dispose();
81
+ }
82
+ /**
83
+ * Internal method to subscribe to a GraphQL query.
84
+ *
85
+ * This method is only exposed for testing and shouldn't be used
86
+ * directly.
87
+ */ _subscribe({ query, variables, onResult, onError: optionsOnError, onComplete = noop }) {
88
+ let payload = {
89
+ query,
90
+ variables: unthunk(variables)
91
+ };
92
+ const [type, operation] = payload.query.split(/ |\(/, 2);
93
+ const removeConnectedListener = this._client.on("connected", ()=>{
94
+ if (this.status === 2) {
95
+ payload = {
96
+ query,
97
+ variables: unthunk(variables)
98
+ };
99
+ log.info("re-sending graphql query via ws", {
100
+ type,
101
+ operation
102
+ }, {
103
+ variables: payload.variables
104
+ });
105
+ }
106
+ });
107
+ const queue = new PQueue({
108
+ concurrency: 1
109
+ });
110
+ const onError = (error)=>optionsOnError(new EditGraphQLError(query, error));
111
+ log.info("sending graphql query via ws", {
112
+ type,
113
+ operation
114
+ }, {
115
+ variables: payload.variables
116
+ });
117
+ const unsubscribe = this._client.subscribe(payload, {
118
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
119
+ next: (result)=>queue.add(()=>onResult(result)).catch(onError),
120
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
121
+ error: (error)=>queue.add(()=>onError(error)),
122
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
123
+ complete: ()=>queue.add(()=>onComplete()).catch(onError)
124
+ });
125
+ return ()=>{
126
+ removeConnectedListener();
127
+ unsubscribe();
128
+ };
129
+ }
130
+ async _query(input) {
131
+ const cookie = loadCookie();
132
+ assert(cookie, "missing cookie when connecting to GraphQL API");
133
+ let subdomain = this.app.slug;
134
+ if (this.app.hasSplitEnvironments) {
135
+ subdomain += "--development";
136
+ }
137
+ const payload = {
138
+ ...input,
139
+ variables: unthunk(input.variables)
140
+ };
141
+ const [type, operation] = payload.query.split(/ |\(/, 2);
142
+ log.info("sending graphql query via http", {
143
+ type,
144
+ operation
145
+ }, {
146
+ variables: payload.variables
147
+ });
148
+ try {
149
+ const json = await http({
150
+ method: "POST",
151
+ url: `https://${subdomain}.${config.domains.app}/edit/api/graphql`,
152
+ headers: {
153
+ cookie
154
+ },
155
+ json: payload,
156
+ responseType: "json",
157
+ resolveBodyOnly: true,
158
+ throwHttpErrors: false
159
+ });
160
+ if (!isObject(json) || !("data" in json) && !("errors" in json)) {
161
+ log.error("received invalid graphql response", {
162
+ error: json
163
+ });
164
+ throw json;
165
+ }
166
+ return json;
167
+ } catch (error) {
168
+ throw new EditGraphQLError(input.query, error);
169
+ }
170
+ }
171
+ constructor(app){
172
+ _define_property(this, "app", void 0);
173
+ // assume the client is going to connect
174
+ _define_property(this, "status", void 0);
175
+ _define_property(this, "_client", void 0);
176
+ this.app = app;
177
+ this.status = 0;
178
+ let subdomain = this.app.slug;
179
+ if (this.app.hasSplitEnvironments) {
180
+ subdomain += "--development";
181
+ }
182
+ this._client = createClient({
183
+ url: `wss://${subdomain}.${config.domains.app}/edit/api/graphql-ws`,
184
+ shouldRetry: ()=>true,
185
+ webSocketImpl: class extends WebSocket {
186
+ constructor(address, protocols, wsOptions){
187
+ // this cookie should be available since we were given an app which requires a cookie to load
188
+ const cookie = loadCookie();
189
+ assert(cookie, "missing cookie when connecting to GraphQL API");
190
+ super(address, protocols, {
191
+ ...wsOptions,
192
+ headers: {
193
+ ...wsOptions?.headers,
194
+ "user-agent": config.versionFull,
195
+ cookie
196
+ }
197
+ });
198
+ }
199
+ },
200
+ on: {
201
+ connecting: ()=>{
202
+ switch(this.status){
203
+ case 1:
204
+ this.status = 2;
205
+ log.info("reconnecting");
206
+ break;
207
+ case 2:
208
+ log.info("retrying");
209
+ break;
210
+ default:
211
+ log.info("connecting");
212
+ break;
213
+ }
214
+ },
215
+ connected: ()=>{
216
+ if (this.status === 2) {
217
+ log.info("reconnected");
218
+ } else {
219
+ log.info("connected");
220
+ }
221
+ // let the other on connected listeners see what status we're in
222
+ setImmediate(()=>this.status = 0);
223
+ },
224
+ closed: (e)=>{
225
+ const event = e;
226
+ if (event.wasClean) {
227
+ log.info("connection closed");
228
+ return;
229
+ }
230
+ if (this.status === 0) {
231
+ this.status = 1;
232
+ log.info("disconnected");
233
+ }
234
+ },
235
+ error: (error)=>{
236
+ if (this.status === 2) {
237
+ log.error("failed to reconnect", {
238
+ error
239
+ });
240
+ } else {
241
+ log.error("connection error", {
242
+ error
243
+ });
244
+ }
245
+ }
246
+ }
247
+ });
248
+ }
249
+ }
250
+ export class EditGraphQLError extends CLIError {
251
+ render() {
252
+ let body = "";
253
+ switch(true){
254
+ case isGraphQLErrors(this.cause):
255
+ {
256
+ const errors = uniq(this.cause.map((x)=>x.message));
257
+ body = sprint`
258
+ Gadget responded with the following ${pluralize("error", errors.length, false)}:
259
+
260
+ • ${errors.join("\n • ")}
261
+ `;
262
+ break;
263
+ }
264
+ case isCloseEvent(this.cause):
265
+ body = "The connection to Gadget closed unexpectedly.";
266
+ break;
267
+ case isErrorEvent(this.cause) || isError(this.cause):
268
+ body = this.cause.message;
269
+ break;
270
+ default:
271
+ body = this.cause;
272
+ break;
273
+ }
274
+ return this.message + "\n\n" + body;
275
+ }
276
+ constructor(query, cause){
277
+ super("An error occurred while communicating with Gadget");
278
+ _define_property(this, "query", void 0);
279
+ _define_property(this, "isBug", void 0);
280
+ _define_property(this, "cause", void 0);
281
+ this.query = query;
282
+ this.isBug = IsBug.MAYBE;
283
+ // ErrorEvent and CloseEvent aren't serializable, so we reconstruct
284
+ // them into an object. We discard the `target` property because
285
+ // it's large and not that useful
286
+ if (isErrorEvent(cause)) {
287
+ this.cause = {
288
+ type: cause.type,
289
+ message: cause.message,
290
+ error: serializeError(cause.error)
291
+ };
292
+ } else if (isCloseEvent(cause)) {
293
+ this.cause = {
294
+ type: cause.type,
295
+ code: cause.code,
296
+ reason: cause.reason,
297
+ wasClean: cause.wasClean
298
+ };
299
+ } else {
300
+ assert(isString(cause) || isError(cause) || isGraphQLErrors(cause), "cause must be a string, Error, GraphQLError[], CloseEvent, or ErrorEvent");
301
+ this.cause = cause;
302
+ }
303
+ }
304
+ }
305
+ export const REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION = sprint(/* GraphQL */ `
306
+ subscription RemoteFileSyncEvents($localFilesVersion: String!) {
307
+ remoteFileSyncEvents(localFilesVersion: $localFilesVersion, encoding: base64) {
308
+ remoteFilesVersion
309
+ changed {
310
+ path
311
+ mode
312
+ content
313
+ encoding
314
+ }
315
+ deleted {
316
+ path
317
+ }
318
+ }
319
+ }
320
+ `);
321
+ export const REMOTE_FILES_VERSION_QUERY = sprint(/* GraphQL */ `
322
+ query RemoteFilesVersion {
323
+ remoteFilesVersion
324
+ }
325
+ `);
326
+ export const PUBLISH_FILE_SYNC_EVENTS_MUTATION = sprint(/* GraphQL */ `
327
+ mutation PublishFileSyncEvents($input: PublishFileSyncEventsInput!) {
328
+ publishFileSyncEvents(input: $input) {
329
+ remoteFilesVersion
330
+ }
331
+ }
332
+ `);
333
+ export const FILE_SYNC_FILES_QUERY = sprint(/* GraphQL */ `
334
+ query FileSyncFiles($paths: [String!]!, $filesVersion: String, $encoding: FileSyncEncoding) {
335
+ fileSyncFiles(paths: $paths, filesVersion: $filesVersion, encoding: $encoding) {
336
+ filesVersion
337
+ files {
338
+ path
339
+ mode
340
+ content
341
+ encoding
342
+ }
343
+ }
344
+ }
345
+ `);
346
+ export const FILE_SYNC_HASHES_QUERY = sprint(/* GraphQL */ `
347
+ query FileSyncHashes($filesVersion: String) {
348
+ fileSyncHashes(filesVersion: $filesVersion) {
349
+ filesVersion
350
+ hashes
351
+ }
352
+ }
353
+ `);
354
+ export const FILE_SYNC_COMPARISON_HASHES_QUERY = sprint(/* GraphQL */ `
355
+ query FileSyncComparisonHashes($filesVersion: String!) {
356
+ fileSyncComparisonHashes(filesVersion: $filesVersion) {
357
+ filesVersionHashes {
358
+ filesVersion
359
+ hashes
360
+ }
361
+ latestFilesVersionHashes {
362
+ filesVersion
363
+ hashes
364
+ }
365
+ }
366
+ }
367
+ `);
368
+ export const REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION = sprint(/* GraphQL */ `
369
+ subscription publishStatus($localFilesVersion: String!, $force: Boolean) {
370
+ publishStatus(localFilesVersion: $localFilesVersion, force: $force) {
371
+ remoteFilesVersion
372
+ progress
373
+ issues {
374
+ severity
375
+ message
376
+ node {
377
+ type
378
+ key
379
+ name
380
+ fieldType
381
+ parentKey
382
+ parentApiIdentifier
383
+ }
384
+ }
385
+ }
386
+ }
387
+ `);
388
+
389
+ //# sourceMappingURL=edit-graphql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/services/app/edit-graphql.ts"],"sourcesContent":["import type { GraphQLError } from \"graphql\";\nimport type { ExecutionResult } from \"graphql-ws\";\nimport { createClient } from \"graphql-ws\";\nimport assert from \"node:assert\";\nimport type { ClientRequestArgs } from \"node:http\";\nimport PQueue from \"p-queue\";\nimport pluralize from \"pluralize\";\nimport type { JsonObject, Promisable } from \"type-fest\";\nimport type { CloseEvent, ErrorEvent } from \"ws\";\nimport WebSocket from \"ws\";\nimport type {\n FileSyncComparisonHashesQuery,\n FileSyncComparisonHashesQueryVariables,\n FileSyncFilesQuery,\n FileSyncFilesQueryVariables,\n FileSyncHashesQuery,\n FileSyncHashesQueryVariables,\n PublishFileSyncEventsMutation,\n PublishFileSyncEventsMutationVariables,\n PublishStatusSubscription,\n PublishStatusSubscriptionVariables,\n RemoteFileSyncEventsSubscription,\n RemoteFileSyncEventsSubscriptionVariables,\n RemoteFilesVersionQuery,\n RemoteFilesVersionQueryVariables,\n} from \"../../__generated__/graphql.js\";\nimport { config } from \"../config/config.js\";\nimport { loadCookie } from \"../http/auth.js\";\nimport { http } from \"../http/http.js\";\nimport { createLogger } from \"../output/log/logger.js\";\nimport { CLIError, IsBug } from \"../output/report.js\";\nimport { sprint } from \"../output/sprint.js\";\nimport { uniq } from \"../util/collection.js\";\nimport { noop, unthunk, type Thunk } from \"../util/function.js\";\nimport { isCloseEvent, isError, isErrorEvent, isGraphQLErrors, isObject, isString } from \"../util/is.js\";\nimport { serializeError } from \"../util/object.js\";\nimport type { App } from \"./app.js\";\n\nenum ConnectionStatus {\n CONNECTED,\n DISCONNECTED,\n RECONNECTING,\n}\n\nconst log = createLogger({ name: \"edit-graphql\" });\n\n/**\n * EditGraphQL is a GraphQL client connected to a Gadget application's\n * /edit/api/graphql-ws endpoint.\n */\nexport class EditGraphQL {\n // assume the client is going to connect\n status = ConnectionStatus.CONNECTED;\n\n private _client: ReturnType<typeof createClient>;\n\n constructor(readonly app: App) {\n let subdomain = this.app.slug;\n if (this.app.hasSplitEnvironments) {\n subdomain += \"--development\";\n }\n\n this._client = createClient({\n url: `wss://${subdomain}.${config.domains.app}/edit/api/graphql-ws`,\n shouldRetry: () => true,\n webSocketImpl: class extends WebSocket {\n constructor(address: string | URL, protocols?: string | string[], wsOptions?: WebSocket.ClientOptions | ClientRequestArgs) {\n // this cookie should be available since we were given an app which requires a cookie to load\n const cookie = loadCookie();\n assert(cookie, \"missing cookie when connecting to GraphQL API\");\n\n super(address, protocols, {\n ...wsOptions,\n headers: {\n ...wsOptions?.headers,\n \"user-agent\": config.versionFull,\n cookie,\n },\n });\n }\n },\n on: {\n connecting: () => {\n switch (this.status) {\n case ConnectionStatus.DISCONNECTED:\n this.status = ConnectionStatus.RECONNECTING;\n log.info(\"reconnecting\");\n break;\n case ConnectionStatus.RECONNECTING:\n log.info(\"retrying\");\n break;\n default:\n log.info(\"connecting\");\n break;\n }\n },\n connected: () => {\n if (this.status === ConnectionStatus.RECONNECTING) {\n log.info(\"reconnected\");\n } else {\n log.info(\"connected\");\n }\n\n // let the other on connected listeners see what status we're in\n setImmediate(() => (this.status = ConnectionStatus.CONNECTED));\n },\n closed: (e) => {\n const event = e as CloseEvent;\n if (event.wasClean) {\n log.info(\"connection closed\");\n return;\n }\n\n if (this.status === ConnectionStatus.CONNECTED) {\n this.status = ConnectionStatus.DISCONNECTED;\n log.info(\"disconnected\");\n }\n },\n error: (error) => {\n if (this.status === ConnectionStatus.RECONNECTING) {\n log.error(\"failed to reconnect\", { error });\n } else {\n log.error(\"connection error\", { error });\n }\n },\n },\n });\n }\n\n /**\n * Subscribe to a GraphQL query.\n *\n * This method is typically used to subscribe to a GraphQL\n * subscription. If you want to execute a GraphQL query or mutation,\n * use {@link EditGraphQL.query} instead.\n *\n * @param payload The query and variables to send to the server.\n * @param sink The callbacks to invoke when the server responds.\n * @returns A function to unsubscribe from the subscription.\n */\n subscribe<Query extends GraphQLQuery>({\n onData,\n ...options\n }: {\n query: Query;\n variables?: Thunk<Query[\"Variables\"]> | null;\n onData: (data: Query[\"Data\"]) => Promisable<void>;\n onError: (error: EditGraphQLError) => Promisable<void>;\n onComplete?: () => Promisable<void>;\n }): () => void {\n const unsubscribe = this._subscribe({\n ...options,\n onResult: async (result) => {\n if (result.errors) {\n unsubscribe();\n await options.onError(new EditGraphQLError(options.query, result.errors));\n return;\n }\n\n if (!result.data) {\n unsubscribe();\n await options.onError(new EditGraphQLError(options.query, \"Received a GraphQL response without errors or data\"));\n return;\n }\n\n await onData(result.data);\n },\n });\n\n return unsubscribe;\n }\n\n /**\n * Execute a GraphQL query or mutation.\n *\n * @param payload The query and variables to send to the server.\n * @returns The data returned by the server.\n */\n async query<Query extends GraphQLQuery>({\n query,\n variables,\n }: {\n query: Query;\n variables?: Thunk<Query[\"Variables\"]> | null;\n }): Promise<Query[\"Data\"]> {\n const result = await this._query({ query, variables });\n if (result.errors) {\n throw new EditGraphQLError(query, result.errors);\n }\n if (!result.data) {\n throw new EditGraphQLError(query, \"We received a response without data\");\n }\n return result.data;\n }\n\n /**\n * Close the connection to the server.\n */\n async dispose(): Promise<void> {\n await this._client.dispose();\n }\n\n /**\n * Internal method to subscribe to a GraphQL query.\n *\n * This method is only exposed for testing and shouldn't be used\n * directly.\n */\n _subscribe<Query extends GraphQLQuery>({\n query,\n variables,\n onResult,\n onError: optionsOnError,\n onComplete = noop,\n }: {\n query: Query;\n variables?: Thunk<Query[\"Variables\"]> | null;\n onResult: (result: ExecutionResult<Query[\"Data\"], Query[\"Extensions\"]>) => Promisable<void>;\n onError: (error: EditGraphQLError) => Promisable<void>;\n onComplete?: () => Promisable<void>;\n }): () => void {\n let payload = { query, variables: unthunk(variables) };\n const [type, operation] = payload.query.split(/ |\\(/, 2);\n\n const removeConnectedListener = this._client.on(\"connected\", () => {\n if (this.status === ConnectionStatus.RECONNECTING) {\n payload = { query, variables: unthunk(variables) };\n log.info(\"re-sending graphql query via ws\", { type, operation }, { variables: payload.variables });\n }\n });\n\n const queue = new PQueue({ concurrency: 1 });\n const onError = (error: unknown): Promisable<void> => optionsOnError(new EditGraphQLError(query, error));\n\n log.info(\"sending graphql query via ws\", { type, operation }, { variables: payload.variables });\n const unsubscribe = this._client.subscribe<Query[\"Data\"], Query[\"Extensions\"]>(payload, {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n next: (result) => queue.add(() => onResult(result)).catch(onError),\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n error: (error) => queue.add(() => onError(error)),\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n complete: () => queue.add(() => onComplete()).catch(onError),\n });\n\n return () => {\n removeConnectedListener();\n unsubscribe();\n };\n }\n\n private async _query<Query extends GraphQLQuery>(input: {\n query: Query;\n variables?: Thunk<Query[\"Variables\"]> | null;\n }): Promise<ExecutionResult<Query[\"Data\"], Query[\"Extensions\"]>> {\n const cookie = loadCookie();\n assert(cookie, \"missing cookie when connecting to GraphQL API\");\n\n let subdomain = this.app.slug;\n if (this.app.hasSplitEnvironments) {\n subdomain += \"--development\";\n }\n\n const payload = { ...input, variables: unthunk(input.variables) };\n const [type, operation] = payload.query.split(/ |\\(/, 2);\n log.info(\"sending graphql query via http\", { type, operation }, { variables: payload.variables });\n\n try {\n const json = await http({\n method: \"POST\",\n url: `https://${subdomain}.${config.domains.app}/edit/api/graphql`,\n headers: { cookie },\n json: payload,\n responseType: \"json\",\n resolveBodyOnly: true,\n throwHttpErrors: false,\n });\n\n if (!isObject(json) || (!(\"data\" in json) && !(\"errors\" in json))) {\n log.error(\"received invalid graphql response\", { error: json });\n throw json;\n }\n\n return json as Query[\"Result\"];\n } catch (error) {\n throw new EditGraphQLError(input.query, error);\n }\n }\n}\n\nexport class EditGraphQLError extends CLIError {\n isBug = IsBug.MAYBE;\n\n override cause: string | Error | readonly GraphQLError[] | CloseEvent | ErrorEvent;\n\n constructor(\n readonly query: GraphQLQuery,\n cause: unknown,\n ) {\n super(\"An error occurred while communicating with Gadget\");\n\n // ErrorEvent and CloseEvent aren't serializable, so we reconstruct\n // them into an object. We discard the `target` property because\n // it's large and not that useful\n if (isErrorEvent(cause)) {\n this.cause = {\n type: cause.type,\n message: cause.message,\n error: serializeError(cause.error),\n } as ErrorEvent;\n } else if (isCloseEvent(cause)) {\n this.cause = {\n type: cause.type,\n code: cause.code,\n reason: cause.reason,\n wasClean: cause.wasClean,\n } as CloseEvent;\n } else {\n assert(\n isString(cause) || isError(cause) || isGraphQLErrors(cause),\n \"cause must be a string, Error, GraphQLError[], CloseEvent, or ErrorEvent\",\n );\n this.cause = cause;\n }\n }\n\n override render(): string {\n let body = \"\";\n\n switch (true) {\n case isGraphQLErrors(this.cause): {\n const errors = uniq(this.cause.map((x) => x.message));\n body = sprint`\n Gadget responded with the following ${pluralize(\"error\", errors.length, false)}:\n\n • ${errors.join(\"\\n • \")}\n `;\n break;\n }\n case isCloseEvent(this.cause):\n body = \"The connection to Gadget closed unexpectedly.\";\n break;\n case isErrorEvent(this.cause) || isError(this.cause):\n body = this.cause.message;\n break;\n default:\n body = this.cause;\n break;\n }\n\n return this.message + \"\\n\\n\" + body;\n }\n}\n\n/**\n * A GraphQL query with its associated types.\n *\n * At runtime, this type is just a string.\n */\nexport type GraphQLQuery<\n Data extends JsonObject = JsonObject,\n Variables extends JsonObject = JsonObject,\n Extensions extends JsonObject = JsonObject,\n Result extends ExecutionResult<Data, Extensions> = ExecutionResult<Data, Extensions>,\n> = string & {\n Data: Data;\n Variables: Variables;\n Extensions: Extensions;\n Result: Result;\n};\n\nexport const REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION = sprint(/* GraphQL */ `\n subscription RemoteFileSyncEvents($localFilesVersion: String!) {\n remoteFileSyncEvents(localFilesVersion: $localFilesVersion, encoding: base64) {\n remoteFilesVersion\n changed {\n path\n mode\n content\n encoding\n }\n deleted {\n path\n }\n }\n }\n`) as GraphQLQuery<RemoteFileSyncEventsSubscription, RemoteFileSyncEventsSubscriptionVariables>;\n\nexport type REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION = typeof REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION;\n\nexport const REMOTE_FILES_VERSION_QUERY = sprint(/* GraphQL */ `\n query RemoteFilesVersion {\n remoteFilesVersion\n }\n`) as GraphQLQuery<RemoteFilesVersionQuery, RemoteFilesVersionQueryVariables>;\n\nexport type REMOTE_FILES_VERSION_QUERY = typeof REMOTE_FILES_VERSION_QUERY;\n\nexport const PUBLISH_FILE_SYNC_EVENTS_MUTATION = sprint(/* GraphQL */ `\n mutation PublishFileSyncEvents($input: PublishFileSyncEventsInput!) {\n publishFileSyncEvents(input: $input) {\n remoteFilesVersion\n }\n }\n`) as GraphQLQuery<PublishFileSyncEventsMutation, PublishFileSyncEventsMutationVariables>;\n\nexport type PUBLISH_FILE_SYNC_EVENTS_MUTATION = typeof PUBLISH_FILE_SYNC_EVENTS_MUTATION;\n\nexport const FILE_SYNC_FILES_QUERY = sprint(/* GraphQL */ `\n query FileSyncFiles($paths: [String!]!, $filesVersion: String, $encoding: FileSyncEncoding) {\n fileSyncFiles(paths: $paths, filesVersion: $filesVersion, encoding: $encoding) {\n filesVersion\n files {\n path\n mode\n content\n encoding\n }\n }\n }\n`) as GraphQLQuery<FileSyncFilesQuery, FileSyncFilesQueryVariables>;\n\nexport type FILE_SYNC_FILES_QUERY = typeof FILE_SYNC_FILES_QUERY;\n\nexport const FILE_SYNC_HASHES_QUERY = sprint(/* GraphQL */ `\n query FileSyncHashes($filesVersion: String) {\n fileSyncHashes(filesVersion: $filesVersion) {\n filesVersion\n hashes\n }\n }\n`) as GraphQLQuery<FileSyncHashesQuery, FileSyncHashesQueryVariables>;\n\nexport type FILE_SYNC_HASHES_QUERY = typeof FILE_SYNC_HASHES_QUERY;\n\nexport const FILE_SYNC_COMPARISON_HASHES_QUERY = sprint(/* GraphQL */ `\n query FileSyncComparisonHashes($filesVersion: String!) {\n fileSyncComparisonHashes(filesVersion: $filesVersion) {\n filesVersionHashes {\n filesVersion\n hashes\n }\n latestFilesVersionHashes {\n filesVersion\n hashes\n }\n }\n }\n`) as GraphQLQuery<FileSyncComparisonHashesQuery, FileSyncComparisonHashesQueryVariables>;\n\nexport type FILE_SYNC_COMPARISON_HASHES_QUERY = typeof FILE_SYNC_COMPARISON_HASHES_QUERY;\n\nexport const REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION = sprint(/* GraphQL */ `\n subscription publishStatus($localFilesVersion: String!, $force: Boolean) {\n publishStatus(localFilesVersion: $localFilesVersion, force: $force) {\n remoteFilesVersion\n progress\n issues {\n severity\n message\n node {\n type\n key\n name\n fieldType\n parentKey\n parentApiIdentifier\n }\n }\n }\n }\n`) as GraphQLQuery<PublishStatusSubscription, PublishStatusSubscriptionVariables>;\n\nexport type REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION = typeof REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION;\n"],"names":["createClient","assert","PQueue","pluralize","WebSocket","config","loadCookie","http","createLogger","CLIError","IsBug","sprint","uniq","noop","unthunk","isCloseEvent","isError","isErrorEvent","isGraphQLErrors","isObject","isString","serializeError","ConnectionStatus","log","name","EditGraphQL","subscribe","onData","options","unsubscribe","_subscribe","onResult","result","errors","onError","EditGraphQLError","query","data","variables","_query","dispose","_client","optionsOnError","onComplete","payload","type","operation","split","removeConnectedListener","on","status","info","queue","concurrency","error","next","add","catch","complete","input","cookie","subdomain","app","slug","hasSplitEnvironments","json","method","url","domains","headers","responseType","resolveBodyOnly","throwHttpErrors","constructor","shouldRetry","webSocketImpl","address","protocols","wsOptions","versionFull","connecting","connected","setImmediate","closed","e","event","wasClean","render","body","cause","map","x","message","length","join","isBug","MAYBE","code","reason","REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION","REMOTE_FILES_VERSION_QUERY","PUBLISH_FILE_SYNC_EVENTS_MUTATION","FILE_SYNC_FILES_QUERY","FILE_SYNC_HASHES_QUERY","FILE_SYNC_COMPARISON_HASHES_QUERY","REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION"],"mappings":";AAEA,SAASA,YAAY,QAAQ,aAAa;AAC1C,OAAOC,YAAY,cAAc;AAEjC,OAAOC,YAAY,UAAU;AAC7B,OAAOC,eAAe,YAAY;AAGlC,OAAOC,eAAe,KAAK;AAiB3B,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,IAAI,QAAQ,kBAAkB;AACvC,SAASC,YAAY,QAAQ,0BAA0B;AACvD,SAASC,QAAQ,EAAEC,KAAK,QAAQ,sBAAsB;AACtD,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,IAAI,QAAQ,wBAAwB;AAC7C,SAASC,IAAI,EAAEC,OAAO,QAAoB,sBAAsB;AAChE,SAASC,YAAY,EAAEC,OAAO,EAAEC,YAAY,EAAEC,eAAe,EAAEC,QAAQ,EAAEC,QAAQ,QAAQ,gBAAgB;AACzG,SAASC,cAAc,QAAQ,oBAAoB;;UAG9CC;;;;GAAAA,qBAAAA;AAML,MAAMC,MAAMf,aAAa;IAAEgB,MAAM;AAAe;AAEhD;;;CAGC,GACD,OAAO,MAAMC;IA+EX;;;;;;;;;;GAUC,GACDC,UAAsC,EACpCC,MAAM,EACN,GAAGC,SAOJ,EAAc;QACb,MAAMC,cAAc,IAAI,CAACC,UAAU,CAAC;YAClC,GAAGF,OAAO;YACVG,UAAU,OAAOC;gBACf,IAAIA,OAAOC,MAAM,EAAE;oBACjBJ;oBACA,MAAMD,QAAQM,OAAO,CAAC,IAAIC,iBAAiBP,QAAQQ,KAAK,EAAEJ,OAAOC,MAAM;oBACvE;gBACF;gBAEA,IAAI,CAACD,OAAOK,IAAI,EAAE;oBAChBR;oBACA,MAAMD,QAAQM,OAAO,CAAC,IAAIC,iBAAiBP,QAAQQ,KAAK,EAAE;oBAC1D;gBACF;gBAEA,MAAMT,OAAOK,OAAOK,IAAI;YAC1B;QACF;QAEA,OAAOR;IACT;IAEA;;;;;GAKC,GACD,MAAMO,MAAkC,EACtCA,KAAK,EACLE,SAAS,EAIV,EAA0B;QACzB,MAAMN,SAAS,MAAM,IAAI,CAACO,MAAM,CAAC;YAAEH;YAAOE;QAAU;QACpD,IAAIN,OAAOC,MAAM,EAAE;YACjB,MAAM,IAAIE,iBAAiBC,OAAOJ,OAAOC,MAAM;QACjD;QACA,IAAI,CAACD,OAAOK,IAAI,EAAE;YAChB,MAAM,IAAIF,iBAAiBC,OAAO;QACpC;QACA,OAAOJ,OAAOK,IAAI;IACpB;IAEA;;GAEC,GACD,MAAMG,UAAyB;QAC7B,MAAM,IAAI,CAACC,OAAO,CAACD,OAAO;IAC5B;IAEA;;;;;GAKC,GACDV,WAAuC,EACrCM,KAAK,EACLE,SAAS,EACTP,QAAQ,EACRG,SAASQ,cAAc,EACvBC,aAAa9B,IAAI,EAOlB,EAAc;QACb,IAAI+B,UAAU;YAAER;YAAOE,WAAWxB,QAAQwB;QAAW;QACrD,MAAM,CAACO,MAAMC,UAAU,GAAGF,QAAQR,KAAK,CAACW,KAAK,CAAC,QAAQ;QAEtD,MAAMC,0BAA0B,IAAI,CAACP,OAAO,CAACQ,EAAE,CAAC,aAAa;YAC3D,IAAI,IAAI,CAACC,MAAM,QAAoC;gBACjDN,UAAU;oBAAER;oBAAOE,WAAWxB,QAAQwB;gBAAW;gBACjDf,IAAI4B,IAAI,CAAC,mCAAmC;oBAAEN;oBAAMC;gBAAU,GAAG;oBAAER,WAAWM,QAAQN,SAAS;gBAAC;YAClG;QACF;QAEA,MAAMc,QAAQ,IAAIlD,OAAO;YAAEmD,aAAa;QAAE;QAC1C,MAAMnB,UAAU,CAACoB,QAAqCZ,eAAe,IAAIP,iBAAiBC,OAAOkB;QAEjG/B,IAAI4B,IAAI,CAAC,gCAAgC;YAAEN;YAAMC;QAAU,GAAG;YAAER,WAAWM,QAAQN,SAAS;QAAC;QAC7F,MAAMT,cAAc,IAAI,CAACY,OAAO,CAACf,SAAS,CAAqCkB,SAAS;YACtF,kEAAkE;YAClEW,MAAM,CAACvB,SAAWoB,MAAMI,GAAG,CAAC,IAAMzB,SAASC,SAASyB,KAAK,CAACvB;YAC1D,kEAAkE;YAClEoB,OAAO,CAACA,QAAUF,MAAMI,GAAG,CAAC,IAAMtB,QAAQoB;YAC1C,kEAAkE;YAClEI,UAAU,IAAMN,MAAMI,GAAG,CAAC,IAAMb,cAAcc,KAAK,CAACvB;QACtD;QAEA,OAAO;YACLc;YACAnB;QACF;IACF;IAEA,MAAcU,OAAmCoB,KAGhD,EAAgE;QAC/D,MAAMC,SAAStD;QACfL,OAAO2D,QAAQ;QAEf,IAAIC,YAAY,IAAI,CAACC,GAAG,CAACC,IAAI;QAC7B,IAAI,IAAI,CAACD,GAAG,CAACE,oBAAoB,EAAE;YACjCH,aAAa;QACf;QAEA,MAAMjB,UAAU;YAAE,GAAGe,KAAK;YAAErB,WAAWxB,QAAQ6C,MAAMrB,SAAS;QAAE;QAChE,MAAM,CAACO,MAAMC,UAAU,GAAGF,QAAQR,KAAK,CAACW,KAAK,CAAC,QAAQ;QACtDxB,IAAI4B,IAAI,CAAC,kCAAkC;YAAEN;YAAMC;QAAU,GAAG;YAAER,WAAWM,QAAQN,SAAS;QAAC;QAE/F,IAAI;YACF,MAAM2B,OAAO,MAAM1D,KAAK;gBACtB2D,QAAQ;gBACRC,KAAK,CAAC,QAAQ,EAAEN,UAAU,CAAC,EAAExD,OAAO+D,OAAO,CAACN,GAAG,CAAC,iBAAiB,CAAC;gBAClEO,SAAS;oBAAET;gBAAO;gBAClBK,MAAMrB;gBACN0B,cAAc;gBACdC,iBAAiB;gBACjBC,iBAAiB;YACnB;YAEA,IAAI,CAACrD,SAAS8C,SAAU,CAAE,CAAA,UAAUA,IAAG,KAAM,CAAE,CAAA,YAAYA,IAAG,GAAK;gBACjE1C,IAAI+B,KAAK,CAAC,qCAAqC;oBAAEA,OAAOW;gBAAK;gBAC7D,MAAMA;YACR;YAEA,OAAOA;QACT,EAAE,OAAOX,OAAO;YACd,MAAM,IAAInB,iBAAiBwB,MAAMvB,KAAK,EAAEkB;QAC1C;IACF;IAtOAmB,YAAY,AAASX,GAAQ,CAAE;;QAL/B,wCAAwC;QACxCZ,uBAAAA,UAAAA,KAAAA;QAEA,uBAAQT,WAAR,KAAA;aAEqBqB,MAAAA;aAJrBZ;QAKE,IAAIW,YAAY,IAAI,CAACC,GAAG,CAACC,IAAI;QAC7B,IAAI,IAAI,CAACD,GAAG,CAACE,oBAAoB,EAAE;YACjCH,aAAa;QACf;QAEA,IAAI,CAACpB,OAAO,GAAGzC,aAAa;YAC1BmE,KAAK,CAAC,MAAM,EAAEN,UAAU,CAAC,EAAExD,OAAO+D,OAAO,CAACN,GAAG,CAAC,oBAAoB,CAAC;YACnEY,aAAa,IAAM;YACnBC,eAAe,cAAcvE;gBAC3BqE,YAAYG,OAAqB,EAAEC,SAA6B,EAAEC,SAAuD,CAAE;oBACzH,6FAA6F;oBAC7F,MAAMlB,SAAStD;oBACfL,OAAO2D,QAAQ;oBAEf,KAAK,CAACgB,SAASC,WAAW;wBACxB,GAAGC,SAAS;wBACZT,SAAS;4BACP,GAAGS,WAAWT,OAAO;4BACrB,cAAchE,OAAO0E,WAAW;4BAChCnB;wBACF;oBACF;gBACF;YACF;YACAX,IAAI;gBACF+B,YAAY;oBACV,OAAQ,IAAI,CAAC9B,MAAM;wBACjB;4BACE,IAAI,CAACA,MAAM;4BACX3B,IAAI4B,IAAI,CAAC;4BACT;wBACF;4BACE5B,IAAI4B,IAAI,CAAC;4BACT;wBACF;4BACE5B,IAAI4B,IAAI,CAAC;4BACT;oBACJ;gBACF;gBACA8B,WAAW;oBACT,IAAI,IAAI,CAAC/B,MAAM,QAAoC;wBACjD3B,IAAI4B,IAAI,CAAC;oBACX,OAAO;wBACL5B,IAAI4B,IAAI,CAAC;oBACX;oBAEA,gEAAgE;oBAChE+B,aAAa,IAAO,IAAI,CAAChC,MAAM;gBACjC;gBACAiC,QAAQ,CAACC;oBACP,MAAMC,QAAQD;oBACd,IAAIC,MAAMC,QAAQ,EAAE;wBAClB/D,IAAI4B,IAAI,CAAC;wBACT;oBACF;oBAEA,IAAI,IAAI,CAACD,MAAM,QAAiC;wBAC9C,IAAI,CAACA,MAAM;wBACX3B,IAAI4B,IAAI,CAAC;oBACX;gBACF;gBACAG,OAAO,CAACA;oBACN,IAAI,IAAI,CAACJ,MAAM,QAAoC;wBACjD3B,IAAI+B,KAAK,CAAC,uBAAuB;4BAAEA;wBAAM;oBAC3C,OAAO;wBACL/B,IAAI+B,KAAK,CAAC,oBAAoB;4BAAEA;wBAAM;oBACxC;gBACF;YACF;QACF;IACF;AAgKF;AAEA,OAAO,MAAMnB,yBAAyB1B;IAoC3B8E,SAAiB;QACxB,IAAIC,OAAO;QAEX,OAAQ;YACN,KAAKtE,gBAAgB,IAAI,CAACuE,KAAK;gBAAG;oBAChC,MAAMxD,SAASrB,KAAK,IAAI,CAAC6E,KAAK,CAACC,GAAG,CAAC,CAACC,IAAMA,EAAEC,OAAO;oBACnDJ,OAAO7E,MAAM,CAAC;8CACwB,EAAER,UAAU,SAAS8B,OAAO4D,MAAM,EAAE,OAAO;;cAE3E,EAAE5D,OAAO6D,IAAI,CAAC,oBAAoB;QACxC,CAAC;oBACD;gBACF;YACA,KAAK/E,aAAa,IAAI,CAAC0E,KAAK;gBAC1BD,OAAO;gBACP;YACF,KAAKvE,aAAa,IAAI,CAACwE,KAAK,KAAKzE,QAAQ,IAAI,CAACyE,KAAK;gBACjDD,OAAO,IAAI,CAACC,KAAK,CAACG,OAAO;gBACzB;YACF;gBACEJ,OAAO,IAAI,CAACC,KAAK;gBACjB;QACJ;QAEA,OAAO,IAAI,CAACG,OAAO,GAAG,SAASJ;IACjC;IAxDAf,YACE,AAASrC,KAAmB,EAC5BqD,KAAc,CACd;QACA,KAAK,CAAC;;QARRM,uBAAAA,SAAAA,KAAAA;QAEA,uBAASN,SAAT,KAAA;aAGWrD,QAAAA;aALX2D,QAAQrF,MAAMsF,KAAK;QAUjB,mEAAmE;QACnE,gEAAgE;QAChE,iCAAiC;QACjC,IAAI/E,aAAawE,QAAQ;YACvB,IAAI,CAACA,KAAK,GAAG;gBACX5C,MAAM4C,MAAM5C,IAAI;gBAChB+C,SAASH,MAAMG,OAAO;gBACtBtC,OAAOjC,eAAeoE,MAAMnC,KAAK;YACnC;QACF,OAAO,IAAIvC,aAAa0E,QAAQ;YAC9B,IAAI,CAACA,KAAK,GAAG;gBACX5C,MAAM4C,MAAM5C,IAAI;gBAChBoD,MAAMR,MAAMQ,IAAI;gBAChBC,QAAQT,MAAMS,MAAM;gBACpBZ,UAAUG,MAAMH,QAAQ;YAC1B;QACF,OAAO;YACLrF,OACEmB,SAASqE,UAAUzE,QAAQyE,UAAUvE,gBAAgBuE,QACrD;YAEF,IAAI,CAACA,KAAK,GAAGA;QACf;IACF;AA4BF;AAmBA,OAAO,MAAMU,uCAAuCxF,OAAO,WAAW,GAAG,CAAC;;;;;;;;;;;;;;;AAe1E,CAAC,EAA+F;AAIhG,OAAO,MAAMyF,6BAA6BzF,OAAO,WAAW,GAAG,CAAC;;;;AAIhE,CAAC,EAA6E;AAI9E,OAAO,MAAM0F,oCAAoC1F,OAAO,WAAW,GAAG,CAAC;;;;;;AAMvE,CAAC,EAAyF;AAI1F,OAAO,MAAM2F,wBAAwB3F,OAAO,WAAW,GAAG,CAAC;;;;;;;;;;;;AAY3D,CAAC,EAAmE;AAIpE,OAAO,MAAM4F,yBAAyB5F,OAAO,WAAW,GAAG,CAAC;;;;;;;AAO5D,CAAC,EAAqE;AAItE,OAAO,MAAM6F,oCAAoC7F,OAAO,WAAW,GAAG,CAAC;;;;;;;;;;;;;AAavE,CAAC,EAAyF;AAI1F,OAAO,MAAM8F,6CAA6C9F,OAAO,WAAW,GAAG,CAAC;;;;;;;;;;;;;;;;;;;AAmBhF,CAAC,EAAiF"}
@@ -0,0 +1,53 @@
1
+ import { _ as _define_property } from "@swc/helpers/_/_define_property";
2
+ import arg from "arg";
3
+ import { CLIError, IsBug, UnexpectedError } from "../output/report.js";
4
+ import { isNil } from "../util/is.js";
5
+ export const parseArgs = (args, options)=>{
6
+ const realSpec = {};
7
+ const defaultValues = {};
8
+ for (const [key, value] of Object.entries(args)){
9
+ if (!("type" in value)) {
10
+ realSpec[key] = value;
11
+ continue;
12
+ }
13
+ realSpec[key] = value.type;
14
+ defaultValues[key] = value.default;
15
+ if (value.alias) {
16
+ for (const alias of Array.isArray(value.alias) ? value.alias : [
17
+ value.alias
18
+ ]){
19
+ realSpec[alias] = key;
20
+ }
21
+ }
22
+ }
23
+ try {
24
+ const parsed = arg(realSpec, options);
25
+ for (const [key, value] of Object.entries(defaultValues)){
26
+ if (isNil(parsed[key])) {
27
+ parsed[key] = value;
28
+ }
29
+ }
30
+ return parsed;
31
+ } catch (error) {
32
+ if (error instanceof arg.ArgError) {
33
+ // convert arg.ArgError to CLIError
34
+ // eslint-disable-next-line no-ex-assign
35
+ error = new ArgError(error.message);
36
+ }
37
+ if (error instanceof CLIError) {
38
+ throw error;
39
+ }
40
+ throw new UnexpectedError(error);
41
+ }
42
+ };
43
+ export class ArgError extends CLIError {
44
+ render() {
45
+ return this.message;
46
+ }
47
+ constructor(...args){
48
+ super(...args);
49
+ _define_property(this, "isBug", IsBug.NO);
50
+ }
51
+ }
52
+
53
+ //# sourceMappingURL=arg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/services/command/arg.ts"],"sourcesContent":["import arg from \"arg\";\nimport type { Simplify } from \"type-fest\";\nimport { CLIError, IsBug, UnexpectedError } from \"../output/report.js\";\nimport { isNil } from \"../util/is.js\";\n\nexport type ArgsSpec = Record<string, ArgDefinition>;\n\ntype ArgDefinition<Handler extends arg.Handler = arg.Handler> =\n | Handler\n | {\n type: Handler;\n alias?: string | string[];\n default?: ReturnType<Handler>;\n };\n\nexport const parseArgs = <Args extends ArgsSpec>(args: Args, options?: arg.Options): ArgsSpecResult<Args> => {\n const realSpec: arg.Spec = {};\n const defaultValues: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(args)) {\n if (!(\"type\" in value)) {\n realSpec[key] = value;\n continue;\n }\n\n realSpec[key] = value.type;\n defaultValues[key] = value.default;\n\n if (value.alias) {\n for (const alias of Array.isArray(value.alias) ? value.alias : [value.alias]) {\n realSpec[alias] = key;\n }\n }\n }\n\n try {\n const parsed = arg(realSpec, options);\n for (const [key, value] of Object.entries(defaultValues)) {\n if (isNil(parsed[key])) {\n parsed[key] = value as never;\n }\n }\n return parsed as ArgsSpecResult<Args>;\n } catch (error: unknown) {\n if (error instanceof arg.ArgError) {\n // convert arg.ArgError to CLIError\n // eslint-disable-next-line no-ex-assign\n error = new ArgError(error.message);\n }\n if (error instanceof CLIError) {\n throw error;\n }\n throw new UnexpectedError(error);\n }\n};\n\nexport class ArgError extends CLIError {\n isBug = IsBug.NO;\n\n protected override render(): string {\n return this.message;\n }\n}\n\nexport type ArgsSpecResult<Spec extends ArgsSpec, Args extends keyof Spec = keyof Spec> = Simplify<{\n [Arg in Args]: Spec[Arg] extends ArgDefinition<infer Handler>\n ? Spec[Arg] extends { default: unknown }\n ? NonNullable<ReturnType<Handler>>\n : ReturnType<Handler> | undefined\n : never;\n}> & { _: string[] };\n"],"names":["arg","CLIError","IsBug","UnexpectedError","isNil","parseArgs","args","options","realSpec","defaultValues","key","value","Object","entries","type","default","alias","Array","isArray","parsed","error","ArgError","message","render","isBug","NO"],"mappings":";AAAA,OAAOA,SAAS,MAAM;AAEtB,SAASC,QAAQ,EAAEC,KAAK,EAAEC,eAAe,QAAQ,sBAAsB;AACvE,SAASC,KAAK,QAAQ,gBAAgB;AAYtC,OAAO,MAAMC,YAAY,CAAwBC,MAAYC;IAC3D,MAAMC,WAAqB,CAAC;IAC5B,MAAMC,gBAAyC,CAAC;IAEhD,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACP,MAAO;QAC/C,IAAI,CAAE,CAAA,UAAUK,KAAI,GAAI;YACtBH,QAAQ,CAACE,IAAI,GAAGC;YAChB;QACF;QAEAH,QAAQ,CAACE,IAAI,GAAGC,MAAMG,IAAI;QAC1BL,aAAa,CAACC,IAAI,GAAGC,MAAMI,OAAO;QAElC,IAAIJ,MAAMK,KAAK,EAAE;YACf,KAAK,MAAMA,SAASC,MAAMC,OAAO,CAACP,MAAMK,KAAK,IAAIL,MAAMK,KAAK,GAAG;gBAACL,MAAMK,KAAK;aAAC,CAAE;gBAC5ER,QAAQ,CAACQ,MAAM,GAAGN;YACpB;QACF;IACF;IAEA,IAAI;QACF,MAAMS,SAASnB,IAAIQ,UAAUD;QAC7B,KAAK,MAAM,CAACG,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACJ,eAAgB;YACxD,IAAIL,MAAMe,MAAM,CAACT,IAAI,GAAG;gBACtBS,MAAM,CAACT,IAAI,GAAGC;YAChB;QACF;QACA,OAAOQ;IACT,EAAE,OAAOC,OAAgB;QACvB,IAAIA,iBAAiBpB,IAAIqB,QAAQ,EAAE;YACjC,mCAAmC;YACnC,wCAAwC;YACxCD,QAAQ,IAAIC,SAASD,MAAME,OAAO;QACpC;QACA,IAAIF,iBAAiBnB,UAAU;YAC7B,MAAMmB;QACR;QACA,MAAM,IAAIjB,gBAAgBiB;IAC5B;AACF,EAAE;AAEF,OAAO,MAAMC,iBAAiBpB;IAGTsB,SAAiB;QAClC,OAAO,IAAI,CAACD,OAAO;IACrB;;;QAJAE,uBAAAA,SAAQtB,MAAMuB,EAAE;;AAKlB"}
@@ -0,0 +1,27 @@
1
+ /* eslint-disable @typescript-eslint/consistent-type-imports */ import assert from "node:assert";
2
+ import { pathToFileURL } from "node:url";
3
+ import { config } from "../config/config.js";
4
+ import { relativeToThisFile } from "../util/paths.js";
5
+ export const AvailableCommands = [
6
+ "sync",
7
+ "deploy",
8
+ "list",
9
+ "login",
10
+ "logout",
11
+ "whoami",
12
+ "version"
13
+ ];
14
+ export const isAvailableCommand = (command)=>{
15
+ return AvailableCommands.includes(command);
16
+ };
17
+ export const importCommand = async (cmd)=>{
18
+ assert(isAvailableCommand(cmd), `invalid command: ${cmd}`);
19
+ let commandPath = relativeToThisFile(`../../commands/${cmd}.js`);
20
+ if (config.windows) {
21
+ // https://github.com/nodejs/node/issues/31710
22
+ commandPath = pathToFileURL(commandPath).toString();
23
+ }
24
+ return await import(commandPath);
25
+ };
26
+
27
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/services/command/command.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/consistent-type-imports */\nimport assert from \"node:assert\";\nimport { pathToFileURL } from \"node:url\";\nimport type { Promisable } from \"type-fest\";\nimport type { rootArgs } from \"../../commands/root.js\";\nimport { config } from \"../config/config.js\";\nimport { relativeToThisFile } from \"../util/paths.js\";\nimport type { ArgsSpec } from \"./arg.js\";\nimport type { Context } from \"./context.js\";\n\nexport const AvailableCommands = [\"sync\", \"deploy\", \"list\", \"login\", \"logout\", \"whoami\", \"version\"] as const;\n\nexport type AvailableCommand = (typeof AvailableCommands)[number];\n\nexport const isAvailableCommand = (command: string): command is AvailableCommand => {\n return AvailableCommands.includes(command as AvailableCommand);\n};\n\nexport const importCommand = async (cmd: AvailableCommand): Promise<CommandSpec> => {\n assert(isAvailableCommand(cmd), `invalid command: ${cmd}`);\n let commandPath = relativeToThisFile(`../../commands/${cmd}.js`);\n if (config.windows) {\n // https://github.com/nodejs/node/issues/31710\n commandPath = pathToFileURL(commandPath).toString();\n }\n return (await import(commandPath)) as CommandSpec;\n};\n\nexport type CommandSpec<Args extends ArgsSpec = ArgsSpec, ParentArgsSpec extends ArgsSpec = typeof rootArgs> = {\n args?: Args;\n usage: () => string;\n command: (ctx: Context<Args, ParentArgsSpec>) => Promisable<void>;\n};\n\nexport type Command<Spec extends ArgsSpec = ArgsSpec, ParentSpec extends ArgsSpec = typeof rootArgs> = CommandSpec<\n Spec,\n ParentSpec\n>[\"command\"];\n\nexport type Usage = CommandSpec[\"usage\"];\n"],"names":["assert","pathToFileURL","config","relativeToThisFile","AvailableCommands","isAvailableCommand","command","includes","importCommand","cmd","commandPath","windows","toString"],"mappings":"AAAA,6DAA6D,GAC7D,OAAOA,YAAY,cAAc;AACjC,SAASC,aAAa,QAAQ,WAAW;AAGzC,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,kBAAkB,QAAQ,mBAAmB;AAItD,OAAO,MAAMC,oBAAoB;IAAC;IAAQ;IAAU;IAAQ;IAAS;IAAU;IAAU;CAAU,CAAU;AAI7G,OAAO,MAAMC,qBAAqB,CAACC;IACjC,OAAOF,kBAAkBG,QAAQ,CAACD;AACpC,EAAE;AAEF,OAAO,MAAME,gBAAgB,OAAOC;IAClCT,OAAOK,mBAAmBI,MAAM,CAAC,iBAAiB,EAAEA,IAAI,CAAC;IACzD,IAAIC,cAAcP,mBAAmB,CAAC,eAAe,EAAEM,IAAI,GAAG,CAAC;IAC/D,IAAIP,OAAOS,OAAO,EAAE;QAClB,8CAA8C;QAC9CD,cAAcT,cAAcS,aAAaE,QAAQ;IACnD;IACA,OAAQ,MAAM,MAAM,CAACF;AACvB,EAAE"}
@@ -0,0 +1,60 @@
1
+ import { _ as _define_property } from "@swc/helpers/_/_define_property";
2
+ import assert from "node:assert";
3
+ import { createLogger } from "../output/log/logger.js";
4
+ import { isFunction } from "../util/is.js";
5
+ import { parseArgs } from "./arg.js";
6
+ export class Context extends AbortController {
7
+ extend({ args = {}, logName }) {
8
+ const ctx = new Context(args, {
9
+ args: this.args,
10
+ logName
11
+ });
12
+ this.onAbort(()=>ctx.abort());
13
+ return ctx;
14
+ }
15
+ onAbort(callbackOrOptions, callback) {
16
+ let options = {
17
+ once: true
18
+ };
19
+ if (isFunction(callbackOrOptions)) {
20
+ callback = callbackOrOptions;
21
+ } else {
22
+ options = {
23
+ ...options,
24
+ ...callbackOrOptions
25
+ };
26
+ }
27
+ this.signal.addEventListener("abort", // eslint-disable-next-line @typescript-eslint/no-misused-promises
28
+ async ()=>{
29
+ try {
30
+ assert(callback, "callback must have been provided");
31
+ await callback(this.signal.reason);
32
+ } catch (error) {
33
+ this.log.error("error during cancel", {
34
+ error
35
+ });
36
+ }
37
+ }, options);
38
+ }
39
+ constructor(args, options){
40
+ super();
41
+ _define_property(this, "log", void 0);
42
+ _define_property(this, "args", void 0);
43
+ if (options?.args) {
44
+ assert(!options.argv, "argv and args cannot be used together");
45
+ options.argv = options.args._;
46
+ }
47
+ this.args = {
48
+ ...options?.args,
49
+ ...parseArgs(args, options)
50
+ };
51
+ this.log = createLogger({
52
+ name: options?.logName || "context",
53
+ fields: {
54
+ args: this.args
55
+ }
56
+ });
57
+ }
58
+ }
59
+
60
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/services/command/context.ts"],"sourcesContent":["import type arg from \"arg\";\nimport assert from \"node:assert\";\nimport type { rootArgs } from \"../../commands/root.js\";\nimport { createLogger, type Logger } from \"../output/log/logger.js\";\nimport type { AnyVoid } from \"../util/function.js\";\nimport { isFunction } from \"../util/is.js\";\nimport { parseArgs, type ArgsSpec, type ArgsSpecResult } from \"./arg.js\";\n\nexport class Context<\n Args extends ArgsSpec = ArgsSpec,\n ParentArgs extends ArgsSpec = typeof rootArgs,\n AllArgs extends ArgsSpec = Args & ParentArgs,\n> extends AbortController {\n readonly log: Logger;\n\n readonly args: ArgsSpecResult<AllArgs>;\n\n constructor(args: Args, options?: arg.Options & { args?: ArgsSpecResult<ParentArgs>; logName?: string }) {\n super();\n if (options?.args) {\n assert(!options.argv, \"argv and args cannot be used together\");\n options.argv = options.args._;\n }\n this.args = { ...options?.args, ...parseArgs(args, options) } as ArgsSpecResult<AllArgs>;\n this.log = createLogger({ name: options?.logName || \"context\", fields: { args: this.args } });\n }\n\n extend<ExtendedArgs extends ArgsSpec>({\n args = {} as ExtendedArgs,\n logName,\n }: {\n args?: ExtendedArgs;\n logName?: string;\n }): Context<ExtendedArgs, AllArgs> {\n const ctx = new Context(args, { args: this.args, logName });\n this.onAbort(() => ctx.abort());\n return ctx;\n }\n\n onAbort(callback: OnAbort): void;\n onAbort(options: { once?: boolean }, callback: OnAbort): void;\n onAbort(callbackOrOptions: { once?: boolean } | OnAbort, callback?: OnAbort): void {\n let options = { once: true };\n if (isFunction(callbackOrOptions)) {\n callback = callbackOrOptions;\n } else {\n options = { ...options, ...callbackOrOptions };\n }\n\n this.signal.addEventListener(\n \"abort\",\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async () => {\n try {\n assert(callback, \"callback must have been provided\");\n await callback(this.signal.reason);\n } catch (error: unknown) {\n this.log.error(\"error during cancel\", { error });\n }\n },\n options,\n );\n }\n}\n\nexport type OnAbort = (reason: unknown) => AnyVoid;\n"],"names":["assert","createLogger","isFunction","parseArgs","Context","AbortController","extend","args","logName","ctx","onAbort","abort","callbackOrOptions","callback","options","once","signal","addEventListener","reason","error","log","constructor","argv","_","name","fields"],"mappings":";AACA,OAAOA,YAAY,cAAc;AAEjC,SAASC,YAAY,QAAqB,0BAA0B;AAEpE,SAASC,UAAU,QAAQ,gBAAgB;AAC3C,SAASC,SAAS,QAA4C,WAAW;AAEzE,OAAO,MAAMC,gBAIHC;IAeRC,OAAsC,EACpCC,OAAO,CAAC,CAAiB,EACzBC,OAAO,EAIR,EAAkC;QACjC,MAAMC,MAAM,IAAIL,QAAQG,MAAM;YAAEA,MAAM,IAAI,CAACA,IAAI;YAAEC;QAAQ;QACzD,IAAI,CAACE,OAAO,CAAC,IAAMD,IAAIE,KAAK;QAC5B,OAAOF;IACT;IAIAC,QAAQE,iBAA+C,EAAEC,QAAkB,EAAQ;QACjF,IAAIC,UAAU;YAAEC,MAAM;QAAK;QAC3B,IAAIb,WAAWU,oBAAoB;YACjCC,WAAWD;QACb,OAAO;YACLE,UAAU;gBAAE,GAAGA,OAAO;gBAAE,GAAGF,iBAAiB;YAAC;QAC/C;QAEA,IAAI,CAACI,MAAM,CAACC,gBAAgB,CAC1B,SACA,kEAAkE;QAClE;YACE,IAAI;gBACFjB,OAAOa,UAAU;gBACjB,MAAMA,SAAS,IAAI,CAACG,MAAM,CAACE,MAAM;YACnC,EAAE,OAAOC,OAAgB;gBACvB,IAAI,CAACC,GAAG,CAACD,KAAK,CAAC,uBAAuB;oBAAEA;gBAAM;YAChD;QACF,GACAL;IAEJ;IA7CAO,YAAYd,IAAU,EAAEO,OAA+E,CAAE;QACvG,KAAK;QALP,uBAASM,OAAT,KAAA;QAEA,uBAASb,QAAT,KAAA;QAIE,IAAIO,SAASP,MAAM;YACjBP,OAAO,CAACc,QAAQQ,IAAI,EAAE;YACtBR,QAAQQ,IAAI,GAAGR,QAAQP,IAAI,CAACgB,CAAC;QAC/B;QACA,IAAI,CAAChB,IAAI,GAAG;YAAE,GAAGO,SAASP,IAAI;YAAE,GAAGJ,UAAUI,MAAMO,QAAQ;QAAC;QAC5D,IAAI,CAACM,GAAG,GAAGnB,aAAa;YAAEuB,MAAMV,SAASN,WAAW;YAAWiB,QAAQ;gBAAElB,MAAM,IAAI,CAACA,IAAI;YAAC;QAAE;IAC7F;AAsCF"}