@maxceem/agw 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -73475,7 +73475,6 @@ var mgmtHandoff = sqliteTable(
73475
73475
  initiatingCredentialId: text("initiating_credential_id").notNull(),
73476
73476
  submissionProofHash: text("submission_proof_hash").notNull(),
73477
73477
  pollProofHash: text("poll_proof_hash").notNull(),
73478
- humanCodeHash: text("human_code_hash"),
73479
73478
  consumedAt: integer2("consumed_at"),
73480
73479
  outcome: text("outcome"),
73481
73480
  expiresAt: integer2("expires_at").notNull(),
@@ -76317,7 +76316,6 @@ var CliOperationRequestSchema = external_exports.object({
76317
76316
  }).strict();
76318
76317
  var CliSubmissionRequestSchema = external_exports.object({
76319
76318
  submissionToken: CliProofSchema,
76320
- humanCode: external_exports.string().max(40).optional(),
76321
76319
  approve: external_exports.literal(true).optional(),
76322
76320
  allowServiceAccess: external_exports.boolean().optional(),
76323
76321
  email: external_exports.email().optional(),
@@ -76338,6 +76336,26 @@ var CliAccountSchema = external_exports.object({
76338
76336
  claimed: external_exports.boolean(),
76339
76337
  expiresAt: external_exports.string().nullable()
76340
76338
  });
76339
+ var CliBrowserDetailsResponseSchema = external_exports.object({
76340
+ kind: CliOperationRequestSchema.shape.kind,
76341
+ payload: external_exports.record(external_exports.string(), external_exports.unknown()),
76342
+ account: CliAccountSchema,
76343
+ signedIn: external_exports.boolean(),
76344
+ googleEnabled: external_exports.boolean(),
76345
+ expiresAt: external_exports.string()
76346
+ });
76347
+ var CliBrowserSubmitResponseSchema = external_exports.object({
76348
+ state: external_exports.literal("completed"),
76349
+ message: external_exports.string()
76350
+ });
76351
+ var CliBrowserRegisterResponseSchema = external_exports.object({
76352
+ token: external_exports.string().nullable().optional(),
76353
+ redirect: external_exports.boolean().optional()
76354
+ });
76355
+ var CliBrowserGoogleResponseSchema = external_exports.object({
76356
+ url: external_exports.string(),
76357
+ redirect: external_exports.boolean().optional()
76358
+ });
76341
76359
  var CliCredentialSchema = external_exports.object({
76342
76360
  token: external_exports.string()
76343
76361
  });
@@ -76352,7 +76370,6 @@ var CliOperationResponseSchema = external_exports.object({
76352
76370
  url: external_exports.url(),
76353
76371
  expiresAt: external_exports.string(),
76354
76372
  state: external_exports.enum(["pending", "completed", "failed", "expired"]),
76355
- humanCode: external_exports.string().optional(),
76356
76373
  deployment: CliDeploymentSchema
76357
76374
  });
76358
76375
  var CliOperationResultSchema = external_exports.object({
@@ -76668,6 +76685,208 @@ async function bootstrap(c) {
76668
76685
  }
76669
76686
  __name(bootstrap, "bootstrap");
76670
76687
 
76688
+ // src/routes/cli/operations.ts
76689
+ init_errors();
76690
+ function browserPath(id) {
76691
+ return `/cli/approve/${encodeURIComponent(id)}`;
76692
+ }
76693
+ __name(browserPath, "browserPath");
76694
+ async function authState(c, interactive = false) {
76695
+ const auth = createIdentityAuth(c.env, c.req.url, {
76696
+ suppressDefaultOrganization: true
76697
+ });
76698
+ await auth.middleware({
76699
+ apiKeys: !interactive,
76700
+ syncCurrentOrganizationCookie: false
76701
+ })(c, async () => {
76702
+ });
76703
+ return c.get("authState");
76704
+ }
76705
+ __name(authState, "authState");
76706
+ async function challenge(c) {
76707
+ const row = await c.env.DB.prepare(
76708
+ "SELECT * FROM mgmt_handoff WHERE id=?"
76709
+ ).bind(c.req.param("id")).first();
76710
+ if (!row) throw new GatewayError(404, "not_found", "Operation was not found");
76711
+ return row;
76712
+ }
76713
+ __name(challenge, "challenge");
76714
+ function nonSecretPayload(value) {
76715
+ if (Array.isArray(value)) {
76716
+ for (const item of value) nonSecretPayload(item);
76717
+ return;
76718
+ }
76719
+ if (value && typeof value === "object")
76720
+ for (const [key2, item] of Object.entries(value)) {
76721
+ if (/secret|password|token|api.?key/i.test(key2))
76722
+ throw new GatewayError(
76723
+ 400,
76724
+ "invalid_request",
76725
+ "Secrets must be submitted in the browser form"
76726
+ );
76727
+ nonSecretPayload(item);
76728
+ }
76729
+ }
76730
+ __name(nonSecretPayload, "nonSecretPayload");
76731
+ async function createOperation(c) {
76732
+ const input = providerSchemaBody(
76733
+ CliOperationRequestSchema,
76734
+ await cliJson(c.req.raw)
76735
+ );
76736
+ nonSecretPayload(input.payload);
76737
+ const meta3 = deployment(c);
76738
+ const state = await authState(c);
76739
+ const resolved = requireOrganization(state);
76740
+ if (state.credentialType === "session" && c.req.header("origin") !== meta3.consoleOrigin)
76741
+ throw new GatewayError(
76742
+ 403,
76743
+ "forbidden",
76744
+ "Use the first-party console for browser operations"
76745
+ );
76746
+ if (!state.actor || resolved.role !== "owner" && resolved.role !== "admin")
76747
+ throw new GatewayError(
76748
+ 403,
76749
+ "forbidden",
76750
+ "Account administration is required"
76751
+ );
76752
+ const organizationId = resolved.organization.id;
76753
+ const userId = state.actor.id;
76754
+ const credentialId = state.actor.credentialId;
76755
+ const account = await assertAccountAccess(
76756
+ c.env,
76757
+ organizationId,
76758
+ input.kind === "claim" ? "claim" : "setup"
76759
+ );
76760
+ if (input.kind === "claim" && account.claimed)
76761
+ throw new GatewayError(409, "conflict", "Account is already claimed");
76762
+ const pollHash = await digest2(input.pollToken), id = `cli-operation:${pollHash}`;
76763
+ const requestHash = await digest2(JSON.stringify(input.payload));
76764
+ let value = JSON.stringify({ ...input.payload, __requestHash: requestHash });
76765
+ let row = await c.env.DB.prepare(
76766
+ "SELECT * FROM mgmt_handoff WHERE id=?"
76767
+ ).bind(id).first();
76768
+ if (row && (row.kind !== input.kind || row.organization_id !== organizationId || row.initiating_user_id !== userId || JSON.parse(row.request_json).__requestHash !== requestHash))
76769
+ throw new GatewayError(
76770
+ 409,
76771
+ "conflict",
76772
+ "Operation proof is already bound to a different request"
76773
+ );
76774
+ const submissionToken = await derive(input.pollToken, `browser:${meta3.id}`);
76775
+ if (!row) {
76776
+ if (input.kind !== "claim" && !input.kind.endsWith(".add")) {
76777
+ if (typeof input.payload.id !== "string")
76778
+ throw new GatewayError(
76779
+ 400,
76780
+ "invalid_request",
76781
+ "Resource ID is required"
76782
+ );
76783
+ const gateway = input.kind.startsWith("provider-gateway.");
76784
+ const snapshot = await c.env.DB.prepare(
76785
+ gateway ? "SELECT id,type,name,config_json AS config,status,updated_at AS expectedUpdatedAt FROM provider_gateway WHERE id=? AND organization_id=?" : "SELECT id,type,name,slug,base_url AS baseUrl,provider_gateway_id AS providerGatewayId,gateway_route_json AS gatewayRoute,status,updated_at AS expectedUpdatedAt FROM provider WHERE id=? AND organization_id=?"
76786
+ ).bind(input.payload.id, organizationId).first();
76787
+ if (!snapshot)
76788
+ throw new GatewayError(
76789
+ 404,
76790
+ "not_found",
76791
+ "Resource was not found in this account"
76792
+ );
76793
+ value = JSON.stringify({
76794
+ ...input.payload,
76795
+ expectedUpdatedAt: snapshot.expectedUpdatedAt,
76796
+ snapshot,
76797
+ __requestHash: requestHash
76798
+ });
76799
+ }
76800
+ if (input.kind.startsWith("provider.")) {
76801
+ const captured = JSON.parse(value);
76802
+ const snapshot = captured.snapshot;
76803
+ const gatewayId = Object.hasOwn(input.payload, "providerGatewayId") ? input.payload.providerGatewayId : snapshot?.providerGatewayId;
76804
+ if (typeof gatewayId === "string") {
76805
+ const gatewaySnapshot = await c.env.DB.prepare(
76806
+ "SELECT id,type,name,config_json AS config,status,updated_at AS expectedUpdatedAt FROM provider_gateway WHERE id=? AND organization_id=?"
76807
+ ).bind(gatewayId, organizationId).first();
76808
+ if (!gatewaySnapshot)
76809
+ throw new GatewayError(
76810
+ 404,
76811
+ "not_found",
76812
+ "Provider gateway was not found in this account"
76813
+ );
76814
+ value = JSON.stringify({
76815
+ ...captured,
76816
+ gatewaySnapshot,
76817
+ expectedGatewayUpdatedAt: gatewaySnapshot.expectedUpdatedAt
76818
+ });
76819
+ }
76820
+ }
76821
+ await enforceEndpointRateLimit(
76822
+ c.env,
76823
+ `operation:${organizationId ?? c.req.header("cf-connecting-ip") ?? "local"}`,
76824
+ 10,
76825
+ 6e4
76826
+ );
76827
+ const now2 = Date.now();
76828
+ await c.env.DB.prepare(
76829
+ `INSERT OR IGNORE INTO mgmt_handoff(id,kind,request_json,organization_id,initiating_user_id,initiating_credential_id,submission_proof_hash,poll_proof_hash,expires_at,created_at,updated_at)
76830
+ SELECT ?,?,?,?,?,?,?,?,?,?,? WHERE (SELECT COUNT(*) FROM mgmt_handoff WHERE organization_id = ? AND consumed_at IS NULL AND expires_at>?) < 10`
76831
+ ).bind(
76832
+ id,
76833
+ input.kind,
76834
+ value,
76835
+ organizationId,
76836
+ userId,
76837
+ credentialId,
76838
+ await digest2(submissionToken),
76839
+ pollHash,
76840
+ now2 + TTL,
76841
+ now2,
76842
+ now2,
76843
+ organizationId,
76844
+ now2
76845
+ ).run();
76846
+ row = await c.env.DB.prepare(
76847
+ "SELECT * FROM mgmt_handoff WHERE id=?"
76848
+ ).bind(id).first();
76849
+ if (!row)
76850
+ throw new GatewayError(
76851
+ 429,
76852
+ "rate_limited",
76853
+ "Too many pending operations"
76854
+ );
76855
+ }
76856
+ return c.json({
76857
+ id,
76858
+ url: `${meta3.consoleOrigin}${browserPath(id)}#${submissionToken}`,
76859
+ expiresAt: new Date(row.expires_at).toISOString(),
76860
+ state: row.consumed_at ? "completed" : row.expires_at <= Date.now() ? "expired" : "pending",
76861
+ deployment: meta3
76862
+ });
76863
+ }
76864
+ __name(createOperation, "createOperation");
76865
+ async function pollOperation(c) {
76866
+ const row = await challenge(c);
76867
+ const token = c.req.header("authorization")?.replace(/^Bearer /, "");
76868
+ if (!await proofMatches(token, row.poll_proof_hash))
76869
+ throw new GatewayError(403, "forbidden", "Invalid polling proof");
76870
+ const base = {
76871
+ id: row.id,
76872
+ deployment: deployment(c),
76873
+ expiresAt: new Date(row.expires_at).toISOString()
76874
+ };
76875
+ if (row.expires_at <= Date.now())
76876
+ return c.json({ ...base, state: "expired" });
76877
+ if (!row.consumed_at) return c.json({ ...base, state: "pending" });
76878
+ const result = row.outcome ? JSON.parse(row.outcome) : {};
76879
+ const accountId = result.accountId ?? row.organization_id;
76880
+ const account = accountId ? await accountLifecycle(c.env, accountId) : null;
76881
+ return c.json({
76882
+ ...base,
76883
+ state: "completed",
76884
+ result,
76885
+ account
76886
+ });
76887
+ }
76888
+ __name(pollOperation, "pollOperation");
76889
+
76671
76890
  // src/routes/cli/provider-handoff.ts
76672
76891
  init_errors();
76673
76892
 
@@ -80284,207 +80503,6 @@ __name(completeProviderSubmission, "completeProviderSubmission");
80284
80503
  // src/routes/cli/browser.ts
80285
80504
  init_errors();
80286
80505
 
80287
- // src/routes/cli/operations.ts
80288
- init_errors();
80289
- async function authState(c, interactive = false) {
80290
- const auth = createIdentityAuth(c.env, c.req.url, {
80291
- suppressDefaultOrganization: true
80292
- });
80293
- await auth.middleware({
80294
- apiKeys: !interactive,
80295
- syncCurrentOrganizationCookie: false
80296
- })(c, async () => {
80297
- });
80298
- return c.get("authState");
80299
- }
80300
- __name(authState, "authState");
80301
- async function challenge(c) {
80302
- const row = await c.env.DB.prepare(
80303
- "SELECT * FROM mgmt_handoff WHERE id=?"
80304
- ).bind(c.req.param("id")).first();
80305
- if (!row) throw new GatewayError(404, "not_found", "Operation was not found");
80306
- return row;
80307
- }
80308
- __name(challenge, "challenge");
80309
- function nonSecretPayload(value) {
80310
- if (Array.isArray(value)) {
80311
- for (const item of value) nonSecretPayload(item);
80312
- return;
80313
- }
80314
- if (value && typeof value === "object")
80315
- for (const [key2, item] of Object.entries(value)) {
80316
- if (/secret|password|token|api.?key/i.test(key2))
80317
- throw new GatewayError(
80318
- 400,
80319
- "invalid_request",
80320
- "Secrets must be submitted in the browser form"
80321
- );
80322
- nonSecretPayload(item);
80323
- }
80324
- }
80325
- __name(nonSecretPayload, "nonSecretPayload");
80326
- async function createOperation(c) {
80327
- const input = providerSchemaBody(
80328
- CliOperationRequestSchema,
80329
- await cliJson(c.req.raw)
80330
- );
80331
- nonSecretPayload(input.payload);
80332
- const meta3 = deployment(c);
80333
- const state = await authState(c);
80334
- const resolved = requireOrganization(state);
80335
- if (state.credentialType === "session" && c.req.header("origin") !== meta3.consoleOrigin)
80336
- throw new GatewayError(
80337
- 403,
80338
- "forbidden",
80339
- "Use the first-party console for browser operations"
80340
- );
80341
- if (!state.actor || resolved.role !== "owner" && resolved.role !== "admin")
80342
- throw new GatewayError(
80343
- 403,
80344
- "forbidden",
80345
- "Account administration is required"
80346
- );
80347
- const organizationId = resolved.organization.id;
80348
- const userId = state.actor.id;
80349
- const credentialId = state.actor.credentialId;
80350
- const account = await assertAccountAccess(
80351
- c.env,
80352
- organizationId,
80353
- input.kind === "claim" ? "claim" : "setup"
80354
- );
80355
- if (input.kind === "claim" && account.claimed)
80356
- throw new GatewayError(409, "conflict", "Account is already claimed");
80357
- const pollHash = await digest2(input.pollToken), id = `cli-operation:${pollHash}`;
80358
- const requestHash = await digest2(JSON.stringify(input.payload));
80359
- let value = JSON.stringify({ ...input.payload, __requestHash: requestHash });
80360
- let row = await c.env.DB.prepare(
80361
- "SELECT * FROM mgmt_handoff WHERE id=?"
80362
- ).bind(id).first();
80363
- if (row && (row.kind !== input.kind || row.organization_id !== organizationId || row.initiating_user_id !== userId || JSON.parse(row.request_json).__requestHash !== requestHash))
80364
- throw new GatewayError(
80365
- 409,
80366
- "conflict",
80367
- "Operation proof is already bound to a different request"
80368
- );
80369
- const submissionToken = await derive(input.pollToken, `browser:${meta3.id}`);
80370
- const humanCode = (await derive(input.pollToken, `human:${meta3.id}`)).slice(0, 12).toUpperCase();
80371
- if (!row) {
80372
- if (input.kind !== "claim" && !input.kind.endsWith(".add")) {
80373
- if (typeof input.payload.id !== "string")
80374
- throw new GatewayError(
80375
- 400,
80376
- "invalid_request",
80377
- "Resource ID is required"
80378
- );
80379
- const gateway = input.kind.startsWith("provider-gateway.");
80380
- const snapshot = await c.env.DB.prepare(
80381
- gateway ? "SELECT id,type,name,config_json AS config,status,updated_at AS expectedUpdatedAt FROM provider_gateway WHERE id=? AND organization_id=?" : "SELECT id,type,name,slug,base_url AS baseUrl,provider_gateway_id AS providerGatewayId,gateway_route_json AS gatewayRoute,status,updated_at AS expectedUpdatedAt FROM provider WHERE id=? AND organization_id=?"
80382
- ).bind(input.payload.id, organizationId).first();
80383
- if (!snapshot)
80384
- throw new GatewayError(
80385
- 404,
80386
- "not_found",
80387
- "Resource was not found in this account"
80388
- );
80389
- value = JSON.stringify({
80390
- ...input.payload,
80391
- expectedUpdatedAt: snapshot.expectedUpdatedAt,
80392
- snapshot,
80393
- __requestHash: requestHash
80394
- });
80395
- }
80396
- if (input.kind.startsWith("provider.")) {
80397
- const captured = JSON.parse(value);
80398
- const snapshot = captured.snapshot;
80399
- const gatewayId = Object.hasOwn(input.payload, "providerGatewayId") ? input.payload.providerGatewayId : snapshot?.providerGatewayId;
80400
- if (typeof gatewayId === "string") {
80401
- const gatewaySnapshot = await c.env.DB.prepare(
80402
- "SELECT id,type,name,config_json AS config,status,updated_at AS expectedUpdatedAt FROM provider_gateway WHERE id=? AND organization_id=?"
80403
- ).bind(gatewayId, organizationId).first();
80404
- if (!gatewaySnapshot)
80405
- throw new GatewayError(
80406
- 404,
80407
- "not_found",
80408
- "Provider gateway was not found in this account"
80409
- );
80410
- value = JSON.stringify({
80411
- ...captured,
80412
- gatewaySnapshot,
80413
- expectedGatewayUpdatedAt: gatewaySnapshot.expectedUpdatedAt
80414
- });
80415
- }
80416
- }
80417
- await enforceEndpointRateLimit(
80418
- c.env,
80419
- `operation:${organizationId ?? c.req.header("cf-connecting-ip") ?? "local"}`,
80420
- 10,
80421
- 6e4
80422
- );
80423
- const now2 = Date.now();
80424
- await c.env.DB.prepare(
80425
- `INSERT OR IGNORE INTO mgmt_handoff(id,kind,request_json,organization_id,initiating_user_id,initiating_credential_id,submission_proof_hash,poll_proof_hash,human_code_hash,expires_at,created_at,updated_at)
80426
- SELECT ?,?,?,?,?,?,?,?,?,?,?,? WHERE (SELECT COUNT(*) FROM mgmt_handoff WHERE organization_id = ? AND consumed_at IS NULL AND expires_at>?) < 10`
80427
- ).bind(
80428
- id,
80429
- input.kind,
80430
- value,
80431
- organizationId,
80432
- userId,
80433
- credentialId,
80434
- await digest2(submissionToken),
80435
- pollHash,
80436
- await digest2(humanCode),
80437
- now2 + TTL,
80438
- now2,
80439
- now2,
80440
- organizationId,
80441
- now2
80442
- ).run();
80443
- row = await c.env.DB.prepare(
80444
- "SELECT * FROM mgmt_handoff WHERE id=?"
80445
- ).bind(id).first();
80446
- if (!row)
80447
- throw new GatewayError(
80448
- 429,
80449
- "rate_limited",
80450
- "Too many pending operations"
80451
- );
80452
- }
80453
- return c.json({
80454
- id,
80455
- url: `${meta3.consoleOrigin}/v1/cli/browser/${encodeURIComponent(id)}#${submissionToken}`,
80456
- expiresAt: new Date(row.expires_at).toISOString(),
80457
- state: row.consumed_at ? "completed" : row.expires_at <= Date.now() ? "expired" : "pending",
80458
- ...input.kind === "claim" ? { humanCode } : {},
80459
- deployment: meta3
80460
- });
80461
- }
80462
- __name(createOperation, "createOperation");
80463
- async function pollOperation(c) {
80464
- const row = await challenge(c);
80465
- const token = c.req.header("authorization")?.replace(/^Bearer /, "");
80466
- if (!await proofMatches(token, row.poll_proof_hash))
80467
- throw new GatewayError(403, "forbidden", "Invalid polling proof");
80468
- const base = {
80469
- id: row.id,
80470
- deployment: deployment(c),
80471
- expiresAt: new Date(row.expires_at).toISOString()
80472
- };
80473
- if (row.expires_at <= Date.now())
80474
- return c.json({ ...base, state: "expired" });
80475
- if (!row.consumed_at) return c.json({ ...base, state: "pending" });
80476
- const result = row.outcome ? JSON.parse(row.outcome) : {};
80477
- const accountId = result.accountId ?? row.organization_id;
80478
- const account = accountId ? await accountLifecycle(c.env, accountId) : null;
80479
- return c.json({
80480
- ...base,
80481
- state: "completed",
80482
- result,
80483
- account
80484
- });
80485
- }
80486
- __name(pollOperation, "pollOperation");
80487
-
80488
80506
  // src/routes/cli/identity-handoff.ts
80489
80507
  init_errors();
80490
80508
  async function completeIdentity(c, row, allowServiceAccess) {
@@ -80551,7 +80569,7 @@ async function completeIdentity(c, row, allowServiceAccess) {
80551
80569
  __name(completeIdentity, "completeIdentity");
80552
80570
 
80553
80571
  // src/routes/cli/browser.ts
80554
- async function verifiedSubmission(c, codeRequired = false) {
80572
+ async function verifiedSubmission(c) {
80555
80573
  const meta3 = deployment(c);
80556
80574
  if (new URL(c.req.url).origin !== meta3.consoleOrigin)
80557
80575
  throw new GatewayError(404, "not_found", "Page was not found");
@@ -80571,15 +80589,6 @@ async function verifiedSubmission(c, codeRequired = false) {
80571
80589
  throw new GatewayError(410, "invalid_request", "Operation has expired");
80572
80590
  if (!await proofMatches(input.submissionToken, row.submission_proof_hash))
80573
80591
  throw new GatewayError(403, "forbidden", "Invalid submission proof");
80574
- if (codeRequired && !await proofMatches(
80575
- input.humanCode?.trim().toUpperCase(),
80576
- row.human_code_hash
80577
- ))
80578
- throw new GatewayError(
80579
- 403,
80580
- "forbidden",
80581
- "Enter the separate code shown in your CLI"
80582
- );
80583
80592
  await assertAccountAccess(c.env, row.organization_id, row.kind === "claim" ? "claim" : "read");
80584
80593
  return { input, row };
80585
80594
  }
@@ -80605,7 +80614,7 @@ async function browserDetails(c) {
80605
80614
  }
80606
80615
  __name(browserDetails, "browserDetails");
80607
80616
  async function browserRegister(c) {
80608
- const { row, input } = await verifiedSubmission(c, true);
80617
+ const { row, input } = await verifiedSubmission(c);
80609
80618
  if (row.kind !== "claim" || row.consumed_at)
80610
80619
  throw new GatewayError(
80611
80620
  403,
@@ -80631,15 +80640,6 @@ async function browserRegister(c) {
80631
80640
  __name(browserRegister, "browserRegister");
80632
80641
  async function browserSubmit(c) {
80633
80642
  const { row, input } = await verifiedSubmission(c);
80634
- if (row.kind === "claim" && !await proofMatches(
80635
- input.humanCode?.trim().toUpperCase(),
80636
- row.human_code_hash
80637
- ))
80638
- throw new GatewayError(
80639
- 403,
80640
- "forbidden",
80641
- "Enter the separate code shown in your CLI"
80642
- );
80643
80643
  if (input.approve !== true)
80644
80644
  throw new GatewayError(
80645
80645
  400,
@@ -80663,30 +80663,6 @@ async function browserSubmit(c) {
80663
80663
  });
80664
80664
  }
80665
80665
  __name(browserSubmit, "browserSubmit");
80666
- function browserPage(c) {
80667
- const meta3 = deployment(c);
80668
- if (new URL(c.req.url).origin !== meta3.consoleOrigin)
80669
- throw new GatewayError(404, "not_found", "Page was not found");
80670
- const nonce = crypto.randomUUID().replaceAll("-", "");
80671
- c.header(
80672
- "Content-Security-Policy",
80673
- `default-src 'none'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}'; connect-src 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'`
80674
- );
80675
- c.header("Referrer-Policy", "no-referrer");
80676
- c.header("Cache-Control", "no-store");
80677
- c.header("X-Content-Type-Options", "nosniff");
80678
- return c.html(`<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Approve CLI request \xB7 App AI Gateway</title>
80679
- <style nonce="${nonce}">:root{color-scheme:light;font-family:Georgia,serif;color:#17251e;background:#f3f3eb}body{max-width:640px;margin:7vh auto;padding:24px}header{font:13px ui-monospace,monospace;letter-spacing:.12em;color:#48634c}h1{font-weight:400;font-size:40px;line-height:1.1;margin:20px 0}section{background:#fff;padding:28px;border:1px solid #d4dacf;border-radius:8px;margin:20px 0}label{display:block;margin:18px 0 6px}input,select,button{font:16px ui-sans-serif,sans-serif;border:1px solid #9aa89c;border-radius:5px;padding:12px;box-sizing:border-box;width:100%}button{background:#244e38;color:white;margin-top:22px;cursor:pointer}button:disabled{opacity:.5;cursor:wait}input[type=checkbox]{width:auto}pre{white-space:pre-wrap;overflow-wrap:anywhere;font-size:13px}#status{font-family:ui-sans-serif,sans-serif;line-height:1.5}small{font-family:ui-sans-serif,sans-serif;line-height:1.5}</style>
80680
- <header>APP AI GATEWAY / CLI APPROVAL</header><h1>Review the request.</h1><p>Compare the account and action below with your CLI before approving.</p><section><pre id="details">Loading protected request\u2026</pre><form id="signin" hidden><h2>Sign in</h2><label for="email">Email</label><input id="email" type="email" autocomplete="username"><label for="password">Password</label><input id="password" type="password" autocomplete="current-password"><button>Sign in</button><div id="registration" hidden><label for="name">Name for your account</label><input id="name" autocomplete="name"><label for="registrationCode">Separate claim code shown in your CLI</label><input id="registrationCode" autocomplete="off"><button type="button" id="register">Create your login</button></div><button type="button" id="google" hidden>Continue with Google</button></form><form id="approve" hidden><label for="secret" id="secretLabel" hidden>Provider credential</label><input id="secret" type="password" autocomplete="off" hidden><label for="code" id="codeLabel">Separate code shown in your CLI</label><input id="code" autocomplete="off" spellcheck="false" required><label><input id="confirm" type="checkbox" required> I approve this action for the account shown above.</label><label id="ongoingLabel"><input id="ongoing" type="checkbox" checked> Keep this service identity and its role-based management access.</label><button>Approve request</button></form></section><p id="status" role="status"></p><small>This page never displays management credentials. Provider credentials are submitted directly to your gateway.</small>
80681
- <script nonce="${nonce}">let saved=null;try{saved=JSON.parse(sessionStorage.getItem(location.pathname)||'null')}catch{}if(saved&&saved.expiresAt<=Date.now()){sessionStorage.removeItem(location.pathname);saved=null}const token=location.hash.slice(1)||saved?.token||'';history.replaceState(null,'',location.pathname);const base=location.pathname;const details=document.getElementById('details'),status=document.getElementById('status');let current;
80682
- async function call(path,body){const r=await fetch(path,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)});const data=await r.json();if(!r.ok)throw Error(data.error?.message||data.message||'Request failed');return data}
80683
- async function load(){current=await call(base+'/details',{submissionToken:token});sessionStorage.setItem(base,JSON.stringify({token,expiresAt:Date.parse(current.expiresAt)}));details.textContent=JSON.stringify({action:current.kind,account:current.account,configuration:current.payload,expiresAt:current.expiresAt},null,2);const identity=current.kind==='claim';document.getElementById('signin').hidden=!identity||current.signedIn;document.getElementById('registration').hidden=!identity;document.getElementById('google').hidden=!current.googleEnabled;document.getElementById('approve').hidden=identity&&!current.signedIn;const needsSecret=!identity&&!(current.kind==='provider.add'&&current.payload.providerGatewayId);document.getElementById('secret').hidden=!needsSecret;document.getElementById('secret').required=needsSecret;document.getElementById('secretLabel').hidden=!needsSecret;document.getElementById('ongoingLabel').hidden=!identity;document.getElementById('code').required=identity;document.getElementById('code').hidden=!identity;document.getElementById('codeLabel').hidden=!identity;}
80684
- document.getElementById('signin').onsubmit=async e=>{e.preventDefault();try{await call('/v1/auth/sign-in/email',{email:document.getElementById('email').value,password:document.getElementById('password').value});document.getElementById('password').value='';await load()}catch(e){status.textContent=e.message}};
80685
- document.getElementById('register').onclick=async()=>{try{await call(base+'/register',{submissionToken:token,humanCode:document.getElementById('registrationCode').value,email:document.getElementById('email').value,password:document.getElementById('password').value,name:document.getElementById('name').value});document.getElementById('password').value='';await load()}catch(e){status.textContent=e.message}};
80686
- document.getElementById('google').onclick=async()=>{try{const result=await call(current.kind==='claim'?base+'/google':'/v1/auth/sign-in/social',current.kind==='claim'?{submissionToken:token,humanCode:document.getElementById('registrationCode').value}:{provider:'google',callbackURL:location.href});location.href=result.url}catch(e){status.textContent=e.message}};
80687
- document.getElementById('approve').onsubmit=async e=>{e.preventDefault();const b=e.target.querySelector('button');b.disabled=true;try{const value={submissionToken:token,humanCode:document.getElementById('code').value,approve:true,allowServiceAccess:document.getElementById('ongoing').checked};if(!document.getElementById('secret').hidden)value.secret=document.getElementById('secret').value;await call(base+'/submit',value);document.getElementById('secret').value='';status.textContent='Approved. Return to your CLI.';sessionStorage.removeItem(base);e.target.hidden=true}catch(e){status.textContent=e.message;b.disabled=false}};load().catch(e=>status.textContent=e.message);<\/script></html>`);
80688
- }
80689
- __name(browserPage, "browserPage");
80690
80666
 
80691
80667
  // src/routes/cli/oauth.ts
80692
80668
  var CLAIM_OAUTH_COOKIE = "cli_claim_oauth";
@@ -80710,7 +80686,7 @@ async function claimOAuthAuthorized(env2, request) {
80710
80686
  }
80711
80687
  __name(claimOAuthAuthorized, "claimOAuthAuthorized");
80712
80688
  async function browserGoogle(c) {
80713
- const { row } = await verifiedSubmission(c, true);
80689
+ const { row } = await verifiedSubmission(c);
80714
80690
  if (row.kind !== "claim" || row.consumed_at)
80715
80691
  throw new GatewayError(403, "forbidden", "Google registration requires a pending claim");
80716
80692
  const meta3 = deployment(c);
@@ -80719,7 +80695,7 @@ async function browserGoogle(c) {
80719
80695
  const rawResult = await createClaimRegistrationAuth(c.env, c.req.url).auth.api.signInSocial({
80720
80696
  body: {
80721
80697
  provider: "google",
80722
- callbackURL: `${meta3.consoleOrigin}/v1/cli/browser/${encodeURIComponent(row.id)}`
80698
+ callbackURL: `${meta3.consoleOrigin}${browserPath(row.id)}`
80723
80699
  },
80724
80700
  headers: c.req.raw.headers,
80725
80701
  asResponse: true
@@ -80941,7 +80917,7 @@ GROUP BY app_id`).bind(organizationId, month).all();
80941
80917
  __name(organizationMonthUsage, "organizationMonthUsage");
80942
80918
 
80943
80919
  // package.json
80944
- var version4 = "0.1.3";
80920
+ var version4 = "0.1.4";
80945
80921
 
80946
80922
  // src/core/version.ts
80947
80923
  var SERVER_VERSION = version4;
@@ -80984,7 +80960,6 @@ cliRoutes.get("/capabilities", (c) => {
80984
80960
  cliRoutes.post("/bootstrap", bootstrap);
80985
80961
  cliRoutes.post("/operations", createOperation);
80986
80962
  cliRoutes.get("/operations/:id", pollOperation);
80987
- cliRoutes.get("/browser/:id", browserPage);
80988
80963
  cliRoutes.post("/browser/:id/details", browserDetails);
80989
80964
  cliRoutes.post("/browser/:id/submit", browserSubmit);
80990
80965
  cliRoutes.post("/browser/:id/register", browserRegister);
@@ -1 +1 @@
1
- {"version":"0.1.3","sha256":"8fed7ad69620d90506714613cac4dc0ae62450767cd8261f718fa78431caf911"}
1
+ {"version":"0.1.4","sha256":"6822a2a6c387356888ffdbb91cd5359e1fe181bb8d7cbd237bca65c99c91fa79"}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@maxceem/agw",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "App AI Gateway CLI",
6
- "upgradeFrom": ["0.1.2", "0.1.1", "0.1.0"],
6
+ "upgradeFrom": ["0.1.3", "0.1.2", "0.1.1", "0.1.0"],
7
7
  "license": "Apache-2.0",
8
8
  "bin": {
9
9
  "agw": "dist/agw.mjs"