@maxceem/agw 0.1.2 → 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.
- package/README.md +1 -1
- package/dist/agw.mjs +60 -19
- package/dist/release/{0.1.2/console/assets/endpoints-Dnjjwdkn.js → 0.1.4/console/assets/endpoints-BNTBSczQ.js} +1 -1
- package/dist/release/{0.1.2/console/assets/index-D71D9UiI.js → 0.1.4/console/assets/index-BGQQK35_.js} +8 -8
- package/dist/release/0.1.4/console/assets/index-DUtKG6Od.css +2 -0
- package/dist/release/{0.1.2/console/assets/usage-DjvO6eyw.js → 0.1.4/console/assets/usage-CzdJHSbn.js} +1 -1
- package/dist/release/{0.1.2 → 0.1.4}/console/index.html +2 -2
- package/dist/release/0.1.4/manifest.json +26 -0
- package/dist/release/{0.1.2 → 0.1.4}/migrations/0000_initial.sql +0 -1
- package/dist/release/{0.1.2 → 0.1.4}/worker/index.js +246 -260
- package/dist/release-integrity.json +1 -1
- package/package.json +2 -2
- package/dist/release/0.1.2/console/assets/index-CsWBdB28.css +0 -2
- package/dist/release/0.1.2/manifest.json +0 -24
- /package/dist/release/{0.1.2 → 0.1.4}/console/.assetsignore +0 -0
- /package/dist/release/{0.1.2 → 0.1.4}/console/favicon.svg +0 -0
- /package/dist/release/{0.1.2 → 0.1.4}/wrangler.json +0 -0
|
@@ -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(),
|
|
@@ -75661,6 +75660,9 @@ var AppWriteSchema = external_exports.object({
|
|
|
75661
75660
|
config: AppConfigSchema,
|
|
75662
75661
|
status: external_exports.enum(["active", "disabled"]).optional()
|
|
75663
75662
|
}).strict().meta({ id: "AppWrite" });
|
|
75663
|
+
var AppUpdateSchema = AppWriteSchema.extend({
|
|
75664
|
+
revision: external_exports.number().int().positive()
|
|
75665
|
+
}).meta({ id: "AppUpdate" });
|
|
75664
75666
|
var APP_ID_IS_SERVER_ASSIGNED = "id is assigned by the server: omit it and read app.id from the response";
|
|
75665
75667
|
var AppAttestKeyIdSchema = external_exports.string().min(1).max(200);
|
|
75666
75668
|
var ChallengeSchema = external_exports.string().min(1).max(200);
|
|
@@ -76314,7 +76316,6 @@ var CliOperationRequestSchema = external_exports.object({
|
|
|
76314
76316
|
}).strict();
|
|
76315
76317
|
var CliSubmissionRequestSchema = external_exports.object({
|
|
76316
76318
|
submissionToken: CliProofSchema,
|
|
76317
|
-
humanCode: external_exports.string().max(40).optional(),
|
|
76318
76319
|
approve: external_exports.literal(true).optional(),
|
|
76319
76320
|
allowServiceAccess: external_exports.boolean().optional(),
|
|
76320
76321
|
email: external_exports.email().optional(),
|
|
@@ -76335,6 +76336,26 @@ var CliAccountSchema = external_exports.object({
|
|
|
76335
76336
|
claimed: external_exports.boolean(),
|
|
76336
76337
|
expiresAt: external_exports.string().nullable()
|
|
76337
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
|
+
});
|
|
76338
76359
|
var CliCredentialSchema = external_exports.object({
|
|
76339
76360
|
token: external_exports.string()
|
|
76340
76361
|
});
|
|
@@ -76349,7 +76370,6 @@ var CliOperationResponseSchema = external_exports.object({
|
|
|
76349
76370
|
url: external_exports.url(),
|
|
76350
76371
|
expiresAt: external_exports.string(),
|
|
76351
76372
|
state: external_exports.enum(["pending", "completed", "failed", "expired"]),
|
|
76352
|
-
humanCode: external_exports.string().optional(),
|
|
76353
76373
|
deployment: CliDeploymentSchema
|
|
76354
76374
|
});
|
|
76355
76375
|
var CliOperationResultSchema = external_exports.object({
|
|
@@ -76665,6 +76685,208 @@ async function bootstrap(c) {
|
|
|
76665
76685
|
}
|
|
76666
76686
|
__name(bootstrap, "bootstrap");
|
|
76667
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
|
+
|
|
76668
76890
|
// src/routes/cli/provider-handoff.ts
|
|
76669
76891
|
init_errors();
|
|
76670
76892
|
|
|
@@ -80281,207 +80503,6 @@ __name(completeProviderSubmission, "completeProviderSubmission");
|
|
|
80281
80503
|
// src/routes/cli/browser.ts
|
|
80282
80504
|
init_errors();
|
|
80283
80505
|
|
|
80284
|
-
// src/routes/cli/operations.ts
|
|
80285
|
-
init_errors();
|
|
80286
|
-
async function authState(c, interactive = false) {
|
|
80287
|
-
const auth = createIdentityAuth(c.env, c.req.url, {
|
|
80288
|
-
suppressDefaultOrganization: true
|
|
80289
|
-
});
|
|
80290
|
-
await auth.middleware({
|
|
80291
|
-
apiKeys: !interactive,
|
|
80292
|
-
syncCurrentOrganizationCookie: false
|
|
80293
|
-
})(c, async () => {
|
|
80294
|
-
});
|
|
80295
|
-
return c.get("authState");
|
|
80296
|
-
}
|
|
80297
|
-
__name(authState, "authState");
|
|
80298
|
-
async function challenge(c) {
|
|
80299
|
-
const row = await c.env.DB.prepare(
|
|
80300
|
-
"SELECT * FROM mgmt_handoff WHERE id=?"
|
|
80301
|
-
).bind(c.req.param("id")).first();
|
|
80302
|
-
if (!row) throw new GatewayError(404, "not_found", "Operation was not found");
|
|
80303
|
-
return row;
|
|
80304
|
-
}
|
|
80305
|
-
__name(challenge, "challenge");
|
|
80306
|
-
function nonSecretPayload(value) {
|
|
80307
|
-
if (Array.isArray(value)) {
|
|
80308
|
-
for (const item of value) nonSecretPayload(item);
|
|
80309
|
-
return;
|
|
80310
|
-
}
|
|
80311
|
-
if (value && typeof value === "object")
|
|
80312
|
-
for (const [key2, item] of Object.entries(value)) {
|
|
80313
|
-
if (/secret|password|token|api.?key/i.test(key2))
|
|
80314
|
-
throw new GatewayError(
|
|
80315
|
-
400,
|
|
80316
|
-
"invalid_request",
|
|
80317
|
-
"Secrets must be submitted in the browser form"
|
|
80318
|
-
);
|
|
80319
|
-
nonSecretPayload(item);
|
|
80320
|
-
}
|
|
80321
|
-
}
|
|
80322
|
-
__name(nonSecretPayload, "nonSecretPayload");
|
|
80323
|
-
async function createOperation(c) {
|
|
80324
|
-
const input = providerSchemaBody(
|
|
80325
|
-
CliOperationRequestSchema,
|
|
80326
|
-
await cliJson(c.req.raw)
|
|
80327
|
-
);
|
|
80328
|
-
nonSecretPayload(input.payload);
|
|
80329
|
-
const meta3 = deployment(c);
|
|
80330
|
-
const state = await authState(c);
|
|
80331
|
-
const resolved = requireOrganization(state);
|
|
80332
|
-
if (state.credentialType === "session" && c.req.header("origin") !== meta3.consoleOrigin)
|
|
80333
|
-
throw new GatewayError(
|
|
80334
|
-
403,
|
|
80335
|
-
"forbidden",
|
|
80336
|
-
"Use the first-party console for browser operations"
|
|
80337
|
-
);
|
|
80338
|
-
if (!state.actor || resolved.role !== "owner" && resolved.role !== "admin")
|
|
80339
|
-
throw new GatewayError(
|
|
80340
|
-
403,
|
|
80341
|
-
"forbidden",
|
|
80342
|
-
"Account administration is required"
|
|
80343
|
-
);
|
|
80344
|
-
const organizationId = resolved.organization.id;
|
|
80345
|
-
const userId = state.actor.id;
|
|
80346
|
-
const credentialId = state.actor.credentialId;
|
|
80347
|
-
const account = await assertAccountAccess(
|
|
80348
|
-
c.env,
|
|
80349
|
-
organizationId,
|
|
80350
|
-
input.kind === "claim" ? "claim" : "setup"
|
|
80351
|
-
);
|
|
80352
|
-
if (input.kind === "claim" && account.claimed)
|
|
80353
|
-
throw new GatewayError(409, "conflict", "Account is already claimed");
|
|
80354
|
-
const pollHash = await digest2(input.pollToken), id = `cli-operation:${pollHash}`;
|
|
80355
|
-
const requestHash = await digest2(JSON.stringify(input.payload));
|
|
80356
|
-
let value = JSON.stringify({ ...input.payload, __requestHash: requestHash });
|
|
80357
|
-
let row = await c.env.DB.prepare(
|
|
80358
|
-
"SELECT * FROM mgmt_handoff WHERE id=?"
|
|
80359
|
-
).bind(id).first();
|
|
80360
|
-
if (row && (row.kind !== input.kind || row.organization_id !== organizationId || row.initiating_user_id !== userId || JSON.parse(row.request_json).__requestHash !== requestHash))
|
|
80361
|
-
throw new GatewayError(
|
|
80362
|
-
409,
|
|
80363
|
-
"conflict",
|
|
80364
|
-
"Operation proof is already bound to a different request"
|
|
80365
|
-
);
|
|
80366
|
-
const submissionToken = await derive(input.pollToken, `browser:${meta3.id}`);
|
|
80367
|
-
const humanCode = (await derive(input.pollToken, `human:${meta3.id}`)).slice(0, 12).toUpperCase();
|
|
80368
|
-
if (!row) {
|
|
80369
|
-
if (input.kind !== "claim" && !input.kind.endsWith(".add")) {
|
|
80370
|
-
if (typeof input.payload.id !== "string")
|
|
80371
|
-
throw new GatewayError(
|
|
80372
|
-
400,
|
|
80373
|
-
"invalid_request",
|
|
80374
|
-
"Resource ID is required"
|
|
80375
|
-
);
|
|
80376
|
-
const gateway = input.kind.startsWith("provider-gateway.");
|
|
80377
|
-
const snapshot = await c.env.DB.prepare(
|
|
80378
|
-
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=?"
|
|
80379
|
-
).bind(input.payload.id, organizationId).first();
|
|
80380
|
-
if (!snapshot)
|
|
80381
|
-
throw new GatewayError(
|
|
80382
|
-
404,
|
|
80383
|
-
"not_found",
|
|
80384
|
-
"Resource was not found in this account"
|
|
80385
|
-
);
|
|
80386
|
-
value = JSON.stringify({
|
|
80387
|
-
...input.payload,
|
|
80388
|
-
expectedUpdatedAt: snapshot.expectedUpdatedAt,
|
|
80389
|
-
snapshot,
|
|
80390
|
-
__requestHash: requestHash
|
|
80391
|
-
});
|
|
80392
|
-
}
|
|
80393
|
-
if (input.kind.startsWith("provider.")) {
|
|
80394
|
-
const captured = JSON.parse(value);
|
|
80395
|
-
const snapshot = captured.snapshot;
|
|
80396
|
-
const gatewayId = Object.hasOwn(input.payload, "providerGatewayId") ? input.payload.providerGatewayId : snapshot?.providerGatewayId;
|
|
80397
|
-
if (typeof gatewayId === "string") {
|
|
80398
|
-
const gatewaySnapshot = await c.env.DB.prepare(
|
|
80399
|
-
"SELECT id,type,name,config_json AS config,status,updated_at AS expectedUpdatedAt FROM provider_gateway WHERE id=? AND organization_id=?"
|
|
80400
|
-
).bind(gatewayId, organizationId).first();
|
|
80401
|
-
if (!gatewaySnapshot)
|
|
80402
|
-
throw new GatewayError(
|
|
80403
|
-
404,
|
|
80404
|
-
"not_found",
|
|
80405
|
-
"Provider gateway was not found in this account"
|
|
80406
|
-
);
|
|
80407
|
-
value = JSON.stringify({
|
|
80408
|
-
...captured,
|
|
80409
|
-
gatewaySnapshot,
|
|
80410
|
-
expectedGatewayUpdatedAt: gatewaySnapshot.expectedUpdatedAt
|
|
80411
|
-
});
|
|
80412
|
-
}
|
|
80413
|
-
}
|
|
80414
|
-
await enforceEndpointRateLimit(
|
|
80415
|
-
c.env,
|
|
80416
|
-
`operation:${organizationId ?? c.req.header("cf-connecting-ip") ?? "local"}`,
|
|
80417
|
-
10,
|
|
80418
|
-
6e4
|
|
80419
|
-
);
|
|
80420
|
-
const now2 = Date.now();
|
|
80421
|
-
await c.env.DB.prepare(
|
|
80422
|
-
`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)
|
|
80423
|
-
SELECT ?,?,?,?,?,?,?,?,?,?,?,? WHERE (SELECT COUNT(*) FROM mgmt_handoff WHERE organization_id = ? AND consumed_at IS NULL AND expires_at>?) < 10`
|
|
80424
|
-
).bind(
|
|
80425
|
-
id,
|
|
80426
|
-
input.kind,
|
|
80427
|
-
value,
|
|
80428
|
-
organizationId,
|
|
80429
|
-
userId,
|
|
80430
|
-
credentialId,
|
|
80431
|
-
await digest2(submissionToken),
|
|
80432
|
-
pollHash,
|
|
80433
|
-
await digest2(humanCode),
|
|
80434
|
-
now2 + TTL,
|
|
80435
|
-
now2,
|
|
80436
|
-
now2,
|
|
80437
|
-
organizationId,
|
|
80438
|
-
now2
|
|
80439
|
-
).run();
|
|
80440
|
-
row = await c.env.DB.prepare(
|
|
80441
|
-
"SELECT * FROM mgmt_handoff WHERE id=?"
|
|
80442
|
-
).bind(id).first();
|
|
80443
|
-
if (!row)
|
|
80444
|
-
throw new GatewayError(
|
|
80445
|
-
429,
|
|
80446
|
-
"rate_limited",
|
|
80447
|
-
"Too many pending operations"
|
|
80448
|
-
);
|
|
80449
|
-
}
|
|
80450
|
-
return c.json({
|
|
80451
|
-
id,
|
|
80452
|
-
url: `${meta3.consoleOrigin}/v1/cli/browser/${encodeURIComponent(id)}#${submissionToken}`,
|
|
80453
|
-
expiresAt: new Date(row.expires_at).toISOString(),
|
|
80454
|
-
state: row.consumed_at ? "completed" : row.expires_at <= Date.now() ? "expired" : "pending",
|
|
80455
|
-
...input.kind === "claim" ? { humanCode } : {},
|
|
80456
|
-
deployment: meta3
|
|
80457
|
-
});
|
|
80458
|
-
}
|
|
80459
|
-
__name(createOperation, "createOperation");
|
|
80460
|
-
async function pollOperation(c) {
|
|
80461
|
-
const row = await challenge(c);
|
|
80462
|
-
const token = c.req.header("authorization")?.replace(/^Bearer /, "");
|
|
80463
|
-
if (!await proofMatches(token, row.poll_proof_hash))
|
|
80464
|
-
throw new GatewayError(403, "forbidden", "Invalid polling proof");
|
|
80465
|
-
const base = {
|
|
80466
|
-
id: row.id,
|
|
80467
|
-
deployment: deployment(c),
|
|
80468
|
-
expiresAt: new Date(row.expires_at).toISOString()
|
|
80469
|
-
};
|
|
80470
|
-
if (row.expires_at <= Date.now())
|
|
80471
|
-
return c.json({ ...base, state: "expired" });
|
|
80472
|
-
if (!row.consumed_at) return c.json({ ...base, state: "pending" });
|
|
80473
|
-
const result = row.outcome ? JSON.parse(row.outcome) : {};
|
|
80474
|
-
const accountId = result.accountId ?? row.organization_id;
|
|
80475
|
-
const account = accountId ? await accountLifecycle(c.env, accountId) : null;
|
|
80476
|
-
return c.json({
|
|
80477
|
-
...base,
|
|
80478
|
-
state: "completed",
|
|
80479
|
-
result,
|
|
80480
|
-
account
|
|
80481
|
-
});
|
|
80482
|
-
}
|
|
80483
|
-
__name(pollOperation, "pollOperation");
|
|
80484
|
-
|
|
80485
80506
|
// src/routes/cli/identity-handoff.ts
|
|
80486
80507
|
init_errors();
|
|
80487
80508
|
async function completeIdentity(c, row, allowServiceAccess) {
|
|
@@ -80548,7 +80569,7 @@ async function completeIdentity(c, row, allowServiceAccess) {
|
|
|
80548
80569
|
__name(completeIdentity, "completeIdentity");
|
|
80549
80570
|
|
|
80550
80571
|
// src/routes/cli/browser.ts
|
|
80551
|
-
async function verifiedSubmission(c
|
|
80572
|
+
async function verifiedSubmission(c) {
|
|
80552
80573
|
const meta3 = deployment(c);
|
|
80553
80574
|
if (new URL(c.req.url).origin !== meta3.consoleOrigin)
|
|
80554
80575
|
throw new GatewayError(404, "not_found", "Page was not found");
|
|
@@ -80568,15 +80589,6 @@ async function verifiedSubmission(c, codeRequired = false) {
|
|
|
80568
80589
|
throw new GatewayError(410, "invalid_request", "Operation has expired");
|
|
80569
80590
|
if (!await proofMatches(input.submissionToken, row.submission_proof_hash))
|
|
80570
80591
|
throw new GatewayError(403, "forbidden", "Invalid submission proof");
|
|
80571
|
-
if (codeRequired && !await proofMatches(
|
|
80572
|
-
input.humanCode?.trim().toUpperCase(),
|
|
80573
|
-
row.human_code_hash
|
|
80574
|
-
))
|
|
80575
|
-
throw new GatewayError(
|
|
80576
|
-
403,
|
|
80577
|
-
"forbidden",
|
|
80578
|
-
"Enter the separate code shown in your CLI"
|
|
80579
|
-
);
|
|
80580
80592
|
await assertAccountAccess(c.env, row.organization_id, row.kind === "claim" ? "claim" : "read");
|
|
80581
80593
|
return { input, row };
|
|
80582
80594
|
}
|
|
@@ -80602,7 +80614,7 @@ async function browserDetails(c) {
|
|
|
80602
80614
|
}
|
|
80603
80615
|
__name(browserDetails, "browserDetails");
|
|
80604
80616
|
async function browserRegister(c) {
|
|
80605
|
-
const { row, input } = await verifiedSubmission(c
|
|
80617
|
+
const { row, input } = await verifiedSubmission(c);
|
|
80606
80618
|
if (row.kind !== "claim" || row.consumed_at)
|
|
80607
80619
|
throw new GatewayError(
|
|
80608
80620
|
403,
|
|
@@ -80628,15 +80640,6 @@ async function browserRegister(c) {
|
|
|
80628
80640
|
__name(browserRegister, "browserRegister");
|
|
80629
80641
|
async function browserSubmit(c) {
|
|
80630
80642
|
const { row, input } = await verifiedSubmission(c);
|
|
80631
|
-
if (row.kind === "claim" && !await proofMatches(
|
|
80632
|
-
input.humanCode?.trim().toUpperCase(),
|
|
80633
|
-
row.human_code_hash
|
|
80634
|
-
))
|
|
80635
|
-
throw new GatewayError(
|
|
80636
|
-
403,
|
|
80637
|
-
"forbidden",
|
|
80638
|
-
"Enter the separate code shown in your CLI"
|
|
80639
|
-
);
|
|
80640
80643
|
if (input.approve !== true)
|
|
80641
80644
|
throw new GatewayError(
|
|
80642
80645
|
400,
|
|
@@ -80660,30 +80663,6 @@ async function browserSubmit(c) {
|
|
|
80660
80663
|
});
|
|
80661
80664
|
}
|
|
80662
80665
|
__name(browserSubmit, "browserSubmit");
|
|
80663
|
-
function browserPage(c) {
|
|
80664
|
-
const meta3 = deployment(c);
|
|
80665
|
-
if (new URL(c.req.url).origin !== meta3.consoleOrigin)
|
|
80666
|
-
throw new GatewayError(404, "not_found", "Page was not found");
|
|
80667
|
-
const nonce = crypto.randomUUID().replaceAll("-", "");
|
|
80668
|
-
c.header(
|
|
80669
|
-
"Content-Security-Policy",
|
|
80670
|
-
`default-src 'none'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}'; connect-src 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'`
|
|
80671
|
-
);
|
|
80672
|
-
c.header("Referrer-Policy", "no-referrer");
|
|
80673
|
-
c.header("Cache-Control", "no-store");
|
|
80674
|
-
c.header("X-Content-Type-Options", "nosniff");
|
|
80675
|
-
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>
|
|
80676
|
-
<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>
|
|
80677
|
-
<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>
|
|
80678
|
-
<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;
|
|
80679
|
-
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}
|
|
80680
|
-
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'&¤t.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;}
|
|
80681
|
-
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}};
|
|
80682
|
-
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}};
|
|
80683
|
-
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}};
|
|
80684
|
-
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>`);
|
|
80685
|
-
}
|
|
80686
|
-
__name(browserPage, "browserPage");
|
|
80687
80666
|
|
|
80688
80667
|
// src/routes/cli/oauth.ts
|
|
80689
80668
|
var CLAIM_OAUTH_COOKIE = "cli_claim_oauth";
|
|
@@ -80707,7 +80686,7 @@ async function claimOAuthAuthorized(env2, request) {
|
|
|
80707
80686
|
}
|
|
80708
80687
|
__name(claimOAuthAuthorized, "claimOAuthAuthorized");
|
|
80709
80688
|
async function browserGoogle(c) {
|
|
80710
|
-
const { row } = await verifiedSubmission(c
|
|
80689
|
+
const { row } = await verifiedSubmission(c);
|
|
80711
80690
|
if (row.kind !== "claim" || row.consumed_at)
|
|
80712
80691
|
throw new GatewayError(403, "forbidden", "Google registration requires a pending claim");
|
|
80713
80692
|
const meta3 = deployment(c);
|
|
@@ -80716,7 +80695,7 @@ async function browserGoogle(c) {
|
|
|
80716
80695
|
const rawResult = await createClaimRegistrationAuth(c.env, c.req.url).auth.api.signInSocial({
|
|
80717
80696
|
body: {
|
|
80718
80697
|
provider: "google",
|
|
80719
|
-
callbackURL: `${meta3.consoleOrigin}
|
|
80698
|
+
callbackURL: `${meta3.consoleOrigin}${browserPath(row.id)}`
|
|
80720
80699
|
},
|
|
80721
80700
|
headers: c.req.raw.headers,
|
|
80722
80701
|
asResponse: true
|
|
@@ -80938,7 +80917,7 @@ GROUP BY app_id`).bind(organizationId, month).all();
|
|
|
80938
80917
|
__name(organizationMonthUsage, "organizationMonthUsage");
|
|
80939
80918
|
|
|
80940
80919
|
// package.json
|
|
80941
|
-
var version4 = "0.1.
|
|
80920
|
+
var version4 = "0.1.4";
|
|
80942
80921
|
|
|
80943
80922
|
// src/core/version.ts
|
|
80944
80923
|
var SERVER_VERSION = version4;
|
|
@@ -80981,7 +80960,6 @@ cliRoutes.get("/capabilities", (c) => {
|
|
|
80981
80960
|
cliRoutes.post("/bootstrap", bootstrap);
|
|
80982
80961
|
cliRoutes.post("/operations", createOperation);
|
|
80983
80962
|
cliRoutes.get("/operations/:id", pollOperation);
|
|
80984
|
-
cliRoutes.get("/browser/:id", browserPage);
|
|
80985
80963
|
cliRoutes.post("/browser/:id/details", browserDetails);
|
|
80986
80964
|
cliRoutes.post("/browser/:id/submit", browserSubmit);
|
|
80987
80965
|
cliRoutes.post("/browser/:id/register", browserRegister);
|
|
@@ -83660,6 +83638,15 @@ var APP_ID = /^[a-z0-9][a-z0-9-]{0,62}$/u;
|
|
|
83660
83638
|
var APP_ID_MAX_LENGTH = 63;
|
|
83661
83639
|
var APP_ID_SUFFIX_ALPHABET = "0123456789abcdefghjkmnpqrstvwxyz";
|
|
83662
83640
|
var APP_ID_SUFFIX_LENGTH = 12;
|
|
83641
|
+
function appUpdateBody(value) {
|
|
83642
|
+
const { revision, ...write } = value ?? {};
|
|
83643
|
+
if (revision !== void 0 && AppUpdateSchema.shape.revision.safeParse(revision).error) {
|
|
83644
|
+
throw new GatewayError(400, "app_revision_required", APP_REVISION_REQUIRED);
|
|
83645
|
+
}
|
|
83646
|
+
return { ...appBody(write), revision };
|
|
83647
|
+
}
|
|
83648
|
+
__name(appUpdateBody, "appUpdateBody");
|
|
83649
|
+
var APP_REVISION_REQUIRED = "Send the revision the application was read at as revision";
|
|
83663
83650
|
function appBody(value) {
|
|
83664
83651
|
const parsed = AppWriteSchema.safeParse(value);
|
|
83665
83652
|
if (!parsed.success) {
|
|
@@ -83942,7 +83929,6 @@ appRoutes.get("/apps/:app", async (c) => {
|
|
|
83942
83929
|
} catch (error52) {
|
|
83943
83930
|
configError = error52 instanceof Error ? error52.message : String(error52);
|
|
83944
83931
|
}
|
|
83945
|
-
c.header("ETag", `"app-${row.revision}"`);
|
|
83946
83932
|
return c.json({ app: serializeRow(row), resolved, config_error: configError });
|
|
83947
83933
|
});
|
|
83948
83934
|
appRoutes.post("/apps/:app/validate", async (c) => {
|
|
@@ -83979,7 +83965,7 @@ __name(backfillAppLedger, "backfillAppLedger");
|
|
|
83979
83965
|
appRoutes.put("/apps/:app", async (c) => {
|
|
83980
83966
|
await requireEntitlement(c);
|
|
83981
83967
|
const appId = assertAppId(c.req.param("app"));
|
|
83982
|
-
const body =
|
|
83968
|
+
const body = appUpdateBody(await c.req.json());
|
|
83983
83969
|
const db = database(c.env.DB);
|
|
83984
83970
|
const organizationId = c.get("admin").organizationId;
|
|
83985
83971
|
const existing = await db.query.app.findFirst({
|
|
@@ -83987,10 +83973,11 @@ appRoutes.put("/apps/:app", async (c) => {
|
|
|
83987
83973
|
where: and(eq(app.id, appId), eq(app.organizationId, organizationId))
|
|
83988
83974
|
});
|
|
83989
83975
|
if (!existing) throw new GatewayError(404, "app_not_found", "App is not registered");
|
|
83990
|
-
|
|
83991
|
-
|
|
83992
|
-
|
|
83993
|
-
|
|
83976
|
+
if (body.revision === void 0) {
|
|
83977
|
+
throw new GatewayError(400, "app_revision_required", APP_REVISION_REQUIRED);
|
|
83978
|
+
}
|
|
83979
|
+
if (body.revision !== existing.revision) {
|
|
83980
|
+
throw new GatewayError(409, "app_revision_conflict", "The application changed; reload it before saving your changes");
|
|
83994
83981
|
}
|
|
83995
83982
|
const config3 = validatedConfig(
|
|
83996
83983
|
body.config,
|
|
@@ -84007,11 +83994,10 @@ appRoutes.put("/apps/:app", async (c) => {
|
|
|
84007
83994
|
expectedRevision: existing.revision
|
|
84008
83995
|
};
|
|
84009
83996
|
const written = await updateApp(c.env.DB, values);
|
|
84010
|
-
if (!written) throw new GatewayError(
|
|
83997
|
+
if (!written) throw new GatewayError(409, "app_revision_conflict", "The application changed or was removed; reload it before saving your changes");
|
|
84011
83998
|
invalidateAppConfig(appId);
|
|
84012
83999
|
const resolved = await loadAppConfig(c.env, appId);
|
|
84013
84000
|
await backfillAppLedger(c.env, appId, existing.config, resolved);
|
|
84014
|
-
c.header("ETag", `"app-${written.revision}"`);
|
|
84015
84001
|
return c.json(
|
|
84016
84002
|
{ app: serializeRow(written), resolved: asJsonObject(resolved), config_error: null },
|
|
84017
84003
|
200
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.1.
|
|
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
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "App AI Gateway CLI",
|
|
6
|
-
"upgradeFrom": ["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"
|