@orizm/cli 2.2.7 → 3.0.1
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 +111 -4
- package/dist/array-update-CMFUoQEe.mjs +41 -0
- package/dist/array-update-CMFUoQEe.mjs.map +1 -0
- package/dist/array-update-Dch4e9tI.cjs +58 -0
- package/dist/array-update-Dch4e9tI.cjs.map +1 -0
- package/dist/auth-BGW072BP.mjs +18 -0
- package/dist/auth-BGW072BP.mjs.map +1 -0
- package/dist/auth-CNbONZuf.cjs +18 -0
- package/dist/auth-CNbONZuf.cjs.map +1 -0
- package/dist/bucket-DqW-WEYb.mjs +17 -0
- package/dist/bucket-DqW-WEYb.mjs.map +1 -0
- package/dist/bucket-mg5QQORh.cjs +17 -0
- package/dist/bucket-mg5QQORh.cjs.map +1 -0
- package/dist/cli/main.cjs +231 -0
- package/dist/cli/main.cjs.map +1 -0
- package/dist/cli/main.d.cts +1 -0
- package/dist/cli/main.d.mts +1 -0
- package/dist/cli/main.mjs +196 -0
- package/dist/cli/main.mjs.map +1 -0
- package/dist/cms-BJnovGYT.mjs +172 -0
- package/dist/cms-BJnovGYT.mjs.map +1 -0
- package/dist/cms-Cnx-lDGu.cjs +172 -0
- package/dist/cms-Cnx-lDGu.cjs.map +1 -0
- package/dist/codegen-BF5b-u46.cjs +17 -0
- package/dist/codegen-BF5b-u46.cjs.map +1 -0
- package/dist/codegen-DZOB4ttR.mjs +17 -0
- package/dist/codegen-DZOB4ttR.mjs.map +1 -0
- package/dist/config/index.cjs +49 -96
- package/dist/config/index.cjs.map +1 -1
- package/dist/config/index.d.cts +1 -53
- package/dist/config/{index.d.ts → index.d.mts} +29 -28
- package/dist/config/index.d.mts.map +1 -0
- package/dist/config/index.mjs +59 -0
- package/dist/config/index.mjs.map +1 -0
- package/dist/config-loader-BEgS869e.mjs +65 -0
- package/dist/config-loader-BEgS869e.mjs.map +1 -0
- package/dist/config-loader-D8x32gEU.cjs +78 -0
- package/dist/config-loader-D8x32gEU.cjs.map +1 -0
- package/dist/confirm-delete-B9o73U7B.cjs +19 -0
- package/dist/confirm-delete-B9o73U7B.cjs.map +1 -0
- package/dist/confirm-delete-CsWkW69-.mjs +14 -0
- package/dist/confirm-delete-CsWkW69-.mjs.map +1 -0
- package/dist/consumer-C4WiGHWG.mjs +18 -0
- package/dist/consumer-C4WiGHWG.mjs.map +1 -0
- package/dist/consumer-OF6Z_eTP.cjs +95 -0
- package/dist/consumer-OF6Z_eTP.cjs.map +1 -0
- package/dist/consumer-l-8wUK8E.cjs +18 -0
- package/dist/consumer-l-8wUK8E.cjs.map +1 -0
- package/dist/consumer-pU2HyiyA.mjs +95 -0
- package/dist/consumer-pU2HyiyA.mjs.map +1 -0
- package/dist/content-BOb6NC8M.mjs +20 -0
- package/dist/content-BOb6NC8M.mjs.map +1 -0
- package/dist/content-DMjSwor1.cjs +20 -0
- package/dist/content-DMjSwor1.cjs.map +1 -0
- package/dist/create-B-PAOor6.mjs +66 -0
- package/dist/create-B-PAOor6.mjs.map +1 -0
- package/dist/create-B1ZBOqcV.mjs +58 -0
- package/dist/create-B1ZBOqcV.mjs.map +1 -0
- package/dist/create-BNYWcyuQ.cjs +66 -0
- package/dist/create-BNYWcyuQ.cjs.map +1 -0
- package/dist/create-Belwettw.mjs +54 -0
- package/dist/create-Belwettw.mjs.map +1 -0
- package/dist/create-BvERyMKa.cjs +81 -0
- package/dist/create-BvERyMKa.cjs.map +1 -0
- package/dist/create-CC814ixh.mjs +66 -0
- package/dist/create-CC814ixh.mjs.map +1 -0
- package/dist/create-CmOriwGo.cjs +58 -0
- package/dist/create-CmOriwGo.cjs.map +1 -0
- package/dist/create-DJY71sp9.cjs +54 -0
- package/dist/create-DJY71sp9.cjs.map +1 -0
- package/dist/create-Dups0gV2.mjs +81 -0
- package/dist/create-Dups0gV2.mjs.map +1 -0
- package/dist/create-Z-z3LXNW.cjs +66 -0
- package/dist/create-Z-z3LXNW.cjs.map +1 -0
- package/dist/delete-8yZ3j0vX.cjs +59 -0
- package/dist/delete-8yZ3j0vX.cjs.map +1 -0
- package/dist/delete-BOUObrDw.mjs +48 -0
- package/dist/delete-BOUObrDw.mjs.map +1 -0
- package/dist/delete-BSLIXrAh.mjs +59 -0
- package/dist/delete-BSLIXrAh.mjs.map +1 -0
- package/dist/delete-CCTiCYIL.cjs +51 -0
- package/dist/delete-CCTiCYIL.cjs.map +1 -0
- package/dist/delete-CIYY59v_.cjs +48 -0
- package/dist/delete-CIYY59v_.cjs.map +1 -0
- package/dist/delete-CSs5Czlo.mjs +59 -0
- package/dist/delete-CSs5Czlo.mjs.map +1 -0
- package/dist/delete-D4r1ve4v.cjs +56 -0
- package/dist/delete-D4r1ve4v.cjs.map +1 -0
- package/dist/delete-DVrafka1.cjs +56 -0
- package/dist/delete-DVrafka1.cjs.map +1 -0
- package/dist/delete-DhSU-Lx2.mjs +51 -0
- package/dist/delete-DhSU-Lx2.mjs.map +1 -0
- package/dist/delete-DozSxZQ7.cjs +59 -0
- package/dist/delete-DozSxZQ7.cjs.map +1 -0
- package/dist/delete-WpMIIvjj.cjs +56 -0
- package/dist/delete-WpMIIvjj.cjs.map +1 -0
- package/dist/delete-XWJRhBFs.mjs +56 -0
- package/dist/delete-XWJRhBFs.mjs.map +1 -0
- package/dist/delete-YYh_0khQ.mjs +56 -0
- package/dist/delete-YYh_0khQ.mjs.map +1 -0
- package/dist/delete-ZIifaG0i.mjs +56 -0
- package/dist/delete-ZIifaG0i.mjs.map +1 -0
- package/dist/detail-8CXNIhKw.cjs +16 -0
- package/dist/detail-8CXNIhKw.cjs.map +1 -0
- package/dist/detail-DN5jCQ4N.mjs +10 -0
- package/dist/detail-DN5jCQ4N.mjs.map +1 -0
- package/dist/download-oFGzg30E.mjs +68 -0
- package/dist/download-oFGzg30E.mjs.map +1 -0
- package/dist/download-ogGbb3FU.cjs +68 -0
- package/dist/download-ogGbb3FU.cjs.map +1 -0
- package/dist/erd-lKC5NB2l.cjs +124 -0
- package/dist/erd-lKC5NB2l.cjs.map +1 -0
- package/dist/erd-zDoF6I_y.mjs +123 -0
- package/dist/erd-zDoF6I_y.mjs.map +1 -0
- package/dist/get-BBOKSXkh.cjs +48 -0
- package/dist/get-BBOKSXkh.cjs.map +1 -0
- package/dist/get-BiPEF_m-.cjs +57 -0
- package/dist/get-BiPEF_m-.cjs.map +1 -0
- package/dist/get-C7dKoSIc.mjs +47 -0
- package/dist/get-C7dKoSIc.mjs.map +1 -0
- package/dist/get-CgEgETQa.mjs +52 -0
- package/dist/get-CgEgETQa.mjs.map +1 -0
- package/dist/get-DB80UNSR.mjs +47 -0
- package/dist/get-DB80UNSR.mjs.map +1 -0
- package/dist/get-DBxhbN1G.mjs +57 -0
- package/dist/get-DBxhbN1G.mjs.map +1 -0
- package/dist/get-DDB89cOs.mjs +48 -0
- package/dist/get-DDB89cOs.mjs.map +1 -0
- package/dist/get-DjRyK0hJ.cjs +47 -0
- package/dist/get-DjRyK0hJ.cjs.map +1 -0
- package/dist/get-IOU__2RP.cjs +52 -0
- package/dist/get-IOU__2RP.cjs.map +1 -0
- package/dist/get-KdWfYINc.cjs +47 -0
- package/dist/get-KdWfYINc.cjs.map +1 -0
- package/dist/get-RpxdnCKR.mjs +56 -0
- package/dist/get-RpxdnCKR.mjs.map +1 -0
- package/dist/get-jwXRlIBJ.cjs +57 -0
- package/dist/get-jwXRlIBJ.cjs.map +1 -0
- package/dist/group-roles-BIH7q8tf.mjs +36 -0
- package/dist/group-roles-BIH7q8tf.mjs.map +1 -0
- package/dist/group-roles-B_iAZog-.cjs +59 -0
- package/dist/group-roles-B_iAZog-.cjs.map +1 -0
- package/dist/invite-D66DSMvq.mjs +66 -0
- package/dist/invite-D66DSMvq.mjs.map +1 -0
- package/dist/invite-DPygtCoO.cjs +66 -0
- package/dist/invite-DPygtCoO.cjs.map +1 -0
- package/dist/key-C71Ffll9.mjs +17 -0
- package/dist/key-C71Ffll9.mjs.map +1 -0
- package/dist/key-DQr7qRL2.cjs +17 -0
- package/dist/key-DQr7qRL2.cjs.map +1 -0
- package/dist/link-BluFyxEL.mjs +42 -0
- package/dist/link-BluFyxEL.mjs.map +1 -0
- package/dist/link-DYu1Vjlw.cjs +42 -0
- package/dist/link-DYu1Vjlw.cjs.map +1 -0
- package/dist/list-57TUfNFd.mjs +48 -0
- package/dist/list-57TUfNFd.mjs.map +1 -0
- package/dist/list-B0N4-Q-5.mjs +81 -0
- package/dist/list-B0N4-Q-5.mjs.map +1 -0
- package/dist/list-BHvURTWd.cjs +40 -0
- package/dist/list-BHvURTWd.cjs.map +1 -0
- package/dist/list-BRh59EqI.cjs +35 -0
- package/dist/list-BRh59EqI.cjs.map +1 -0
- package/dist/list-Br6Cmi9S.cjs +95 -0
- package/dist/list-Br6Cmi9S.cjs.map +1 -0
- package/dist/list-BsYYq9wT.mjs +40 -0
- package/dist/list-BsYYq9wT.mjs.map +1 -0
- package/dist/list-BwfpuhmJ.cjs +37 -0
- package/dist/list-BwfpuhmJ.cjs.map +1 -0
- package/dist/list-BzLraBnA.cjs +82 -0
- package/dist/list-BzLraBnA.cjs.map +1 -0
- package/dist/list-CFwW0G9f.cjs +49 -0
- package/dist/list-CFwW0G9f.cjs.map +1 -0
- package/dist/list-CU42ERNY.cjs +81 -0
- package/dist/list-CU42ERNY.cjs.map +1 -0
- package/dist/list-CbvEh7eA.mjs +35 -0
- package/dist/list-CbvEh7eA.mjs.map +1 -0
- package/dist/list-D0-QrWmn.cjs +51 -0
- package/dist/list-D0-QrWmn.cjs.map +1 -0
- package/dist/list-D5PSDMWw.mjs +51 -0
- package/dist/list-D5PSDMWw.mjs.map +1 -0
- package/dist/list-DexBclfb.cjs +72 -0
- package/dist/list-DexBclfb.cjs.map +1 -0
- package/dist/list-DlJssPwy.cjs +48 -0
- package/dist/list-DlJssPwy.cjs.map +1 -0
- package/dist/list-DrZYlidZ.mjs +72 -0
- package/dist/list-DrZYlidZ.mjs.map +1 -0
- package/dist/list-ocfd7631.mjs +49 -0
- package/dist/list-ocfd7631.mjs.map +1 -0
- package/dist/list-rAn3uOA7.mjs +37 -0
- package/dist/list-rAn3uOA7.mjs.map +1 -0
- package/dist/list-sQk00GV5.mjs +95 -0
- package/dist/list-sQk00GV5.mjs.map +1 -0
- package/dist/list-vbMaOiza.mjs +82 -0
- package/dist/list-vbMaOiza.mjs.map +1 -0
- package/dist/login-2XcHd4wn.cjs +212 -0
- package/dist/login-2XcHd4wn.cjs.map +1 -0
- package/dist/login-FE_dbWMo.mjs +211 -0
- package/dist/login-FE_dbWMo.mjs.map +1 -0
- package/dist/logout-BDbWrGBm.mjs +35 -0
- package/dist/logout-BDbWrGBm.mjs.map +1 -0
- package/dist/logout-DC5TMJ5_.cjs +35 -0
- package/dist/logout-DC5TMJ5_.cjs.map +1 -0
- package/dist/management-BGYcZB4c.cjs +19 -0
- package/dist/management-BGYcZB4c.cjs.map +1 -0
- package/dist/management-DDACMgbU.mjs +19 -0
- package/dist/management-DDACMgbU.mjs.map +1 -0
- package/dist/mask-B1qD73jb.mjs +22 -0
- package/dist/mask-B1qD73jb.mjs.map +1 -0
- package/dist/mask-CqYLib9p.cjs +40 -0
- package/dist/mask-CqYLib9p.cjs.map +1 -0
- package/dist/oauth-client-CdD0evAV.cjs +170 -0
- package/dist/oauth-client-CdD0evAV.cjs.map +1 -0
- package/dist/oauth-client-QHuDa4fW.mjs +139 -0
- package/dist/oauth-client-QHuDa4fW.mjs.map +1 -0
- package/dist/object-DVqidsEc.cjs +20 -0
- package/dist/object-DVqidsEc.cjs.map +1 -0
- package/dist/object-qdBdEghr.mjs +20 -0
- package/dist/object-qdBdEghr.mjs.map +1 -0
- package/dist/org-C4cVovOM.cjs +14 -0
- package/dist/org-C4cVovOM.cjs.map +1 -0
- package/dist/org-CPhTRTks.mjs +14 -0
- package/dist/org-CPhTRTks.mjs.map +1 -0
- package/dist/org-context-Bewx2NEW.cjs +30 -0
- package/dist/org-context-Bewx2NEW.cjs.map +1 -0
- package/dist/org-context-D0dwWC2M.mjs +25 -0
- package/dist/org-context-D0dwWC2M.mjs.map +1 -0
- package/dist/parse-C8oHgQXx.cjs +229 -0
- package/dist/parse-C8oHgQXx.cjs.map +1 -0
- package/dist/parse-DA0k5AHa.mjs +150 -0
- package/dist/parse-DA0k5AHa.mjs.map +1 -0
- package/dist/project-BX7zvWB1.cjs +20 -0
- package/dist/project-BX7zvWB1.cjs.map +1 -0
- package/dist/project-CaXD3QBs.mjs +20 -0
- package/dist/project-CaXD3QBs.mjs.map +1 -0
- package/dist/project-name-CEoM-OL4.cjs +18 -0
- package/dist/project-name-CEoM-OL4.cjs.map +1 -0
- package/dist/project-name-DNMejnzZ.mjs +12 -0
- package/dist/project-name-DNMejnzZ.mjs.map +1 -0
- package/dist/project-user-Cp7i6orv.mjs +20 -0
- package/dist/project-user-Cp7i6orv.mjs.map +1 -0
- package/dist/project-user-Dm0qR-sh.cjs +20 -0
- package/dist/project-user-Dm0qR-sh.cjs.map +1 -0
- package/dist/push-0u6PDz4E.cjs +166 -0
- package/dist/push-0u6PDz4E.cjs.map +1 -0
- package/dist/push-D7co0keA.mjs +166 -0
- package/dist/push-D7co0keA.mjs.map +1 -0
- package/dist/run-codegen-Ceeosw5x.cjs +272 -0
- package/dist/run-codegen-Ceeosw5x.cjs.map +1 -0
- package/dist/run-codegen-DgaFaIQ1.mjs +190 -0
- package/dist/run-codegen-DgaFaIQ1.mjs.map +1 -0
- package/dist/run-with-context-CVhmzAFZ.mjs +876 -0
- package/dist/run-with-context-CVhmzAFZ.mjs.map +1 -0
- package/dist/run-with-context-DJNnEigg.cjs +943 -0
- package/dist/run-with-context-DJNnEigg.cjs.map +1 -0
- package/dist/schema-B3iRqvYK.cjs +20 -0
- package/dist/schema-B3iRqvYK.cjs.map +1 -0
- package/dist/schema-exG250MU.mjs +20 -0
- package/dist/schema-exG250MU.mjs.map +1 -0
- package/dist/shared-CZZimGxc.mjs +35 -0
- package/dist/shared-CZZimGxc.mjs.map +1 -0
- package/dist/shared-DHRPzzKl.cjs +59 -0
- package/dist/shared-DHRPzzKl.cjs.map +1 -0
- package/dist/status-Dq_NJE71.cjs +49 -0
- package/dist/status-Dq_NJE71.cjs.map +1 -0
- package/dist/status-fWqXzV0P.mjs +49 -0
- package/dist/status-fWqXzV0P.mjs.map +1 -0
- package/dist/table-C74eOSh8.cjs +27 -0
- package/dist/table-C74eOSh8.cjs.map +1 -0
- package/dist/table-MHEfbnWO.mjs +20 -0
- package/dist/table-MHEfbnWO.mjs.map +1 -0
- package/dist/table-event-C7gORNlb.mjs +72 -0
- package/dist/table-event-C7gORNlb.mjs.map +1 -0
- package/dist/table-event-DXkCK29f.cjs +101 -0
- package/dist/table-event-DXkCK29f.cjs.map +1 -0
- package/dist/token-store--9GYVL7N.cjs +139 -0
- package/dist/token-store--9GYVL7N.cjs.map +1 -0
- package/dist/token-store-reCGF86F.mjs +124 -0
- package/dist/token-store-reCGF86F.mjs.map +1 -0
- package/dist/update-B4lv4dAz.mjs +109 -0
- package/dist/update-B4lv4dAz.mjs.map +1 -0
- package/dist/update-BXhSosHG.cjs +171 -0
- package/dist/update-BXhSosHG.cjs.map +1 -0
- package/dist/update-CIH6sSVk.cjs +109 -0
- package/dist/update-CIH6sSVk.cjs.map +1 -0
- package/dist/update-CQ4n4Xuf.mjs +117 -0
- package/dist/update-CQ4n4Xuf.mjs.map +1 -0
- package/dist/update-CuPRoVw3.mjs +171 -0
- package/dist/update-CuPRoVw3.mjs.map +1 -0
- package/dist/update-Cx_2GkQj.cjs +61 -0
- package/dist/update-Cx_2GkQj.cjs.map +1 -0
- package/dist/update-DRnN1kiu.cjs +117 -0
- package/dist/update-DRnN1kiu.cjs.map +1 -0
- package/dist/update-Do9HHWzs.cjs +73 -0
- package/dist/update-Do9HHWzs.cjs.map +1 -0
- package/dist/update-mEmULIau.mjs +73 -0
- package/dist/update-mEmULIau.mjs.map +1 -0
- package/dist/update-rzij1b_o.mjs +61 -0
- package/dist/update-rzij1b_o.mjs.map +1 -0
- package/dist/upload-C43ZXxyb.cjs +95 -0
- package/dist/upload-C43ZXxyb.cjs.map +1 -0
- package/dist/upload-DGgJ1TQk.mjs +94 -0
- package/dist/upload-DGgJ1TQk.mjs.map +1 -0
- package/dist/validate-BpxZ8LTl.cjs +31 -0
- package/dist/validate-BpxZ8LTl.cjs.map +1 -0
- package/dist/validate-Ca0CRo16.mjs +31 -0
- package/dist/validate-Ca0CRo16.mjs.map +1 -0
- package/dist/webhook-CVFmch5W.cjs +20 -0
- package/dist/webhook-CVFmch5W.cjs.map +1 -0
- package/dist/webhook-Cy850dNs.mjs +20 -0
- package/dist/webhook-Cy850dNs.mjs.map +1 -0
- package/package.json +28 -17
- package/bin/index.js +0 -3
- package/dist/cli.cjs +0 -1978
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.cts +0 -2
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -1954
- package/dist/cli.js.map +0 -1
- package/dist/config/index.js +0 -81
- package/dist/config/index.js.map +0 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { r as getOutputState, t as defineCommand } from "./cli/main.mjs";
|
|
2
|
+
import { r as contextArgs } from "./shared-CZZimGxc.mjs";
|
|
3
|
+
import { a as apiErrorFailure, n as runWithContext, u as toResult } from "./run-with-context-CVhmzAFZ.mjs";
|
|
4
|
+
import { t as renderTable } from "./table-MHEfbnWO.mjs";
|
|
5
|
+
import { o as parseIntegerChoice } from "./parse-DA0k5AHa.mjs";
|
|
6
|
+
import { Result } from "@praha/byethrow";
|
|
7
|
+
|
|
8
|
+
//#region src/cli/commands/bucket/object/list.ts
|
|
9
|
+
async function bucketObjectListHandler(ctx, options) {
|
|
10
|
+
const objects = toResult(await ctx.client.GET("/projects/{projectName}/buckets/{bucketName}/objects", { params: {
|
|
11
|
+
path: {
|
|
12
|
+
projectName: ctx.projectName,
|
|
13
|
+
bucketName: options.bucket
|
|
14
|
+
},
|
|
15
|
+
query: {
|
|
16
|
+
limit: options.limit,
|
|
17
|
+
...options.cursor !== void 0 ? { cursor: options.cursor } : {}
|
|
18
|
+
}
|
|
19
|
+
} }));
|
|
20
|
+
if (Result.isFailure(objects)) return apiErrorFailure(objects.error);
|
|
21
|
+
const value = objects.value;
|
|
22
|
+
return Result.succeed({
|
|
23
|
+
json: value,
|
|
24
|
+
text: () => {
|
|
25
|
+
const table = renderTable([
|
|
26
|
+
"KEY",
|
|
27
|
+
"ORIGINAL FILENAME",
|
|
28
|
+
"SIZE",
|
|
29
|
+
"TYPE",
|
|
30
|
+
"CREATED AT"
|
|
31
|
+
], value.objects.map((object) => ({ cells: [
|
|
32
|
+
object.key,
|
|
33
|
+
object.originalFilename,
|
|
34
|
+
String(object.size),
|
|
35
|
+
object.type,
|
|
36
|
+
object.createdAt
|
|
37
|
+
] })), getOutputState().color);
|
|
38
|
+
return value.pagination.nextCursor === null ? table : `${table}\nNext cursor: ${value.pagination.nextCursor}`;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const listArgs = {
|
|
43
|
+
...contextArgs,
|
|
44
|
+
bucket: {
|
|
45
|
+
type: "positional",
|
|
46
|
+
required: true,
|
|
47
|
+
description: "Bucket name"
|
|
48
|
+
},
|
|
49
|
+
limit: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "Max number of objects to return (50, 100, or 200)",
|
|
52
|
+
default: "100"
|
|
53
|
+
},
|
|
54
|
+
cursor: {
|
|
55
|
+
type: "string",
|
|
56
|
+
description: "Cursor returned by the previous page"
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var list_default = defineCommand({
|
|
60
|
+
meta: {
|
|
61
|
+
name: "list",
|
|
62
|
+
description: "List objects in a bucket"
|
|
63
|
+
},
|
|
64
|
+
args: listArgs,
|
|
65
|
+
run: async ({ args }) => {
|
|
66
|
+
const limit = parseIntegerChoice("limit", args.limit, [
|
|
67
|
+
50,
|
|
68
|
+
100,
|
|
69
|
+
200
|
|
70
|
+
]);
|
|
71
|
+
if (Result.isFailure(limit)) return limit;
|
|
72
|
+
return runWithContext(args, (ctx) => bucketObjectListHandler(ctx, {
|
|
73
|
+
bucket: args.bucket,
|
|
74
|
+
limit: limit.value,
|
|
75
|
+
cursor: typeof args.cursor === "string" ? args.cursor : void 0
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
export { list_default as default };
|
|
82
|
+
//# sourceMappingURL=list-vbMaOiza.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-vbMaOiza.mjs","names":[],"sources":["../src/cli/commands/bucket/object/list.ts"],"sourcesContent":["import type { ArgsDef } from \"citty\";\nimport { Result } from \"@praha/byethrow\";\nimport {\n defineCommand,\n type CommandFailure,\n type CommandOutput,\n} from \"../../define-command.js\";\nimport { contextArgs } from \"../../shared.js\";\nimport { runWithContext, type CommandContext } from \"../../run-with-context.js\";\nimport { apiErrorFailure } from \"../../api-errors.js\";\nimport { toResult } from \"../../../api/errors.js\";\nimport { getOutputState } from \"../../../ui/output.js\";\nimport { renderTable } from \"../../../ui/table.js\";\nimport { parseIntegerChoice } from \"../../parse.js\";\n\nexport async function bucketObjectListHandler(\n ctx: CommandContext,\n options: { bucket: string; limit: number; cursor?: string },\n): Promise<Result.Result<CommandOutput | undefined, CommandFailure>> {\n const objects = toResult(\n await ctx.client.GET(\n \"/projects/{projectName}/buckets/{bucketName}/objects\",\n {\n params: {\n path: { projectName: ctx.projectName, bucketName: options.bucket },\n query: {\n limit: options.limit,\n ...(options.cursor !== undefined ? { cursor: options.cursor } : {}),\n },\n },\n },\n ),\n );\n if (Result.isFailure(objects)) return apiErrorFailure(objects.error);\n\n const value = objects.value;\n return Result.succeed({\n json: value,\n text: () => {\n const table = renderTable(\n [\"KEY\", \"ORIGINAL FILENAME\", \"SIZE\", \"TYPE\", \"CREATED AT\"],\n value.objects.map((object) => ({\n cells: [\n object.key,\n object.originalFilename,\n String(object.size),\n object.type,\n object.createdAt,\n ],\n })),\n getOutputState().color,\n );\n return value.pagination.nextCursor === null\n ? table\n : `${table}\\nNext cursor: ${value.pagination.nextCursor}`;\n },\n });\n}\n\nconst listArgs = {\n ...contextArgs,\n bucket: {\n type: \"positional\",\n required: true,\n description: \"Bucket name\",\n },\n limit: {\n type: \"string\",\n description: \"Max number of objects to return (50, 100, or 200)\",\n default: \"100\",\n },\n cursor: {\n type: \"string\",\n description: \"Cursor returned by the previous page\",\n },\n} satisfies ArgsDef;\n\nexport default defineCommand({\n meta: {\n name: \"list\",\n description: \"List objects in a bucket\",\n },\n args: listArgs,\n run: async ({ args }) => {\n const limit = parseIntegerChoice(\"limit\", args.limit, [50, 100, 200]);\n if (Result.isFailure(limit)) return limit;\n\n return runWithContext(args, (ctx) =>\n bucketObjectListHandler(ctx, {\n bucket: args.bucket,\n limit: limit.value,\n cursor: typeof args.cursor === \"string\" ? args.cursor : undefined,\n }),\n );\n },\n});\n"],"mappings":";;;;;;;;AAeA,eAAsB,wBACpB,KACA,SACmE;CACnE,MAAM,UAAU,SACd,MAAM,IAAI,OAAO,IACf,wDACA,EACE,QAAQ;EACN,MAAM;GAAE,aAAa,IAAI;GAAa,YAAY,QAAQ;EAAO;EACjE,OAAO;GACL,OAAO,QAAQ;GACf,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;EACnE;CACF,EACF,CACF,CACF;CACA,IAAI,OAAO,UAAU,OAAO,GAAG,OAAO,gBAAgB,QAAQ,KAAK;CAEnE,MAAM,QAAQ,QAAQ;CACtB,OAAO,OAAO,QAAQ;EACpB,MAAM;EACN,YAAY;GACV,MAAM,QAAQ,YACZ;IAAC;IAAO;IAAqB;IAAQ;IAAQ;GAAY,GACzD,MAAM,QAAQ,KAAK,YAAY,EAC7B,OAAO;IACL,OAAO;IACP,OAAO;IACP,OAAO,OAAO,IAAI;IAClB,OAAO;IACP,OAAO;GACT,EACF,EAAE,GACF,eAAe,CAAC,CAAC,KACnB;GACA,OAAO,MAAM,WAAW,eAAe,OACnC,QACA,GAAG,MAAM,iBAAiB,MAAM,WAAW;EACjD;CACF,CAAC;AACH;AAEA,MAAM,WAAW;CACf,GAAG;CACH,QAAQ;EACN,MAAM;EACN,UAAU;EACV,aAAa;CACf;CACA,OAAO;EACL,MAAM;EACN,aAAa;EACb,SAAS;CACX;CACA,QAAQ;EACN,MAAM;EACN,aAAa;CACf;AACF;AAEA,mBAAe,cAAc;CAC3B,MAAM;EACJ,MAAM;EACN,aAAa;CACf;CACA,MAAM;CACN,KAAK,OAAO,EAAE,WAAW;EACvB,MAAM,QAAQ,mBAAmB,SAAS,KAAK,OAAO;GAAC;GAAI;GAAK;EAAG,CAAC;EACpE,IAAI,OAAO,UAAU,KAAK,GAAG,OAAO;EAEpC,OAAO,eAAe,OAAO,QAC3B,wBAAwB,KAAK;GAC3B,QAAQ,KAAK;GACb,OAAO,MAAM;GACb,QAAQ,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;EAC1D,CAAC,CACH;CACF;AACF,CAAC"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
const require_cli_main = require('./cli/main.cjs');
|
|
2
|
+
const require_shared = require('./shared-DHRPzzKl.cjs');
|
|
3
|
+
const require_token_store = require('./token-store--9GYVL7N.cjs');
|
|
4
|
+
const require_oauth_client = require('./oauth-client-CdD0evAV.cjs');
|
|
5
|
+
let _praha_byethrow = require("@praha/byethrow");
|
|
6
|
+
let _hono_node_server = require("@hono/node-server");
|
|
7
|
+
let hono = require("hono");
|
|
8
|
+
let open = require("open");
|
|
9
|
+
open = require_cli_main.__toESM(open, 1);
|
|
10
|
+
|
|
11
|
+
//#region src/cli/util/base64url.ts
|
|
12
|
+
function encodeBase64Url(bytes) {
|
|
13
|
+
let binary = "";
|
|
14
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
15
|
+
return globalThis.btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/cli/util/random.ts
|
|
20
|
+
function randomBytes(length) {
|
|
21
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(length));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/cli/util/sha256.ts
|
|
26
|
+
async function sha256(data) {
|
|
27
|
+
const view = new Uint8Array(data);
|
|
28
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", view);
|
|
29
|
+
return new Uint8Array(digest);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/cli/auth/pkce.ts
|
|
34
|
+
async function createPkce() {
|
|
35
|
+
const codeVerifier = encodeBase64Url(randomBytes(32));
|
|
36
|
+
return {
|
|
37
|
+
codeVerifier,
|
|
38
|
+
codeChallenge: encodeBase64Url(await sha256(new TextEncoder().encode(codeVerifier))),
|
|
39
|
+
codeChallengeMethod: "S256"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/cli/auth/state.ts
|
|
45
|
+
function createState() {
|
|
46
|
+
return encodeBase64Url(randomBytes(32));
|
|
47
|
+
}
|
|
48
|
+
function verifyState(expected, received) {
|
|
49
|
+
return received !== null && received === expected;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/cli/auth/authorize.ts
|
|
54
|
+
const DEFAULT_TIMEOUT_MS = 300 * 1e3;
|
|
55
|
+
async function authorize(params) {
|
|
56
|
+
const { issuerUrl } = params;
|
|
57
|
+
const pkce = await createPkce();
|
|
58
|
+
const state = createState();
|
|
59
|
+
let resolveCallback = () => {};
|
|
60
|
+
const callbackReceived = new Promise((resolve) => {
|
|
61
|
+
resolveCallback = resolve;
|
|
62
|
+
});
|
|
63
|
+
const app = new hono.Hono();
|
|
64
|
+
app.get("/callback", (c) => {
|
|
65
|
+
const query = c.req.query();
|
|
66
|
+
resolveCallback({
|
|
67
|
+
code: query.code,
|
|
68
|
+
state: query.state,
|
|
69
|
+
error: query.error,
|
|
70
|
+
errorDescription: query.error_description
|
|
71
|
+
});
|
|
72
|
+
return c.html(renderCallbackHtml(query.error == null));
|
|
73
|
+
});
|
|
74
|
+
let listened;
|
|
75
|
+
try {
|
|
76
|
+
listened = await listen(app);
|
|
77
|
+
} catch {
|
|
78
|
+
return _praha_byethrow.Result.fail({ type: "callback_server_failed" });
|
|
79
|
+
}
|
|
80
|
+
const { server, port } = listened;
|
|
81
|
+
try {
|
|
82
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
83
|
+
const authorizationUrl = require_oauth_client.buildAuthorizationUrl({
|
|
84
|
+
issuerUrl,
|
|
85
|
+
redirectUri,
|
|
86
|
+
codeChallenge: pkce.codeChallenge,
|
|
87
|
+
codeChallengeMethod: pkce.codeChallengeMethod,
|
|
88
|
+
state
|
|
89
|
+
});
|
|
90
|
+
await (params.openBrowser ?? open.default)(authorizationUrl).catch(() => {
|
|
91
|
+
params.onAuthorizationUrl?.(authorizationUrl);
|
|
92
|
+
});
|
|
93
|
+
const query = await waitForCallback(callbackReceived, params.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
94
|
+
if (query == null) return _praha_byethrow.Result.fail({ type: "callback_timeout" });
|
|
95
|
+
if (!verifyState(state, query.state ?? null)) return _praha_byethrow.Result.fail({ type: "state_mismatch" });
|
|
96
|
+
if (query.error != null) {
|
|
97
|
+
if (query.error === "access_denied") return _praha_byethrow.Result.fail({
|
|
98
|
+
type: "user_denied",
|
|
99
|
+
description: query.errorDescription
|
|
100
|
+
});
|
|
101
|
+
return _praha_byethrow.Result.fail({
|
|
102
|
+
type: "token_exchange_failed",
|
|
103
|
+
reason: [query.error, query.errorDescription].filter((part) => part != null).join(": ")
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (query.code == null) return _praha_byethrow.Result.fail({
|
|
107
|
+
type: "token_exchange_failed",
|
|
108
|
+
reason: "Authorization response did not include a code"
|
|
109
|
+
});
|
|
110
|
+
const exchanged = await require_oauth_client.exchangeCode({
|
|
111
|
+
issuerUrl,
|
|
112
|
+
code: query.code,
|
|
113
|
+
redirectUri,
|
|
114
|
+
codeVerifier: pkce.codeVerifier
|
|
115
|
+
});
|
|
116
|
+
if (_praha_byethrow.Result.isFailure(exchanged)) return exchanged;
|
|
117
|
+
const claims = await require_oauth_client.verifyIdToken(issuerUrl, exchanged.value.idToken);
|
|
118
|
+
return _praha_byethrow.Result.succeed({
|
|
119
|
+
issuerUrl,
|
|
120
|
+
tokenSet: exchanged.value,
|
|
121
|
+
claims
|
|
122
|
+
});
|
|
123
|
+
} finally {
|
|
124
|
+
await closeServer(server);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function listen(app) {
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
const server = (0, _hono_node_server.serve)({
|
|
130
|
+
fetch: app.fetch,
|
|
131
|
+
hostname: "127.0.0.1",
|
|
132
|
+
port: 0
|
|
133
|
+
}, (info) => resolve({
|
|
134
|
+
server,
|
|
135
|
+
port: info.port
|
|
136
|
+
}));
|
|
137
|
+
server.on("error", (error) => reject(error));
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async function waitForCallback(callbackReceived, timeoutMs) {
|
|
141
|
+
let timer;
|
|
142
|
+
const timedOut = new Promise((resolve) => {
|
|
143
|
+
timer = setTimeout(() => resolve(void 0), timeoutMs);
|
|
144
|
+
});
|
|
145
|
+
try {
|
|
146
|
+
return await Promise.race([callbackReceived, timedOut]);
|
|
147
|
+
} finally {
|
|
148
|
+
if (timer != null) clearTimeout(timer);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async function closeServer(server) {
|
|
152
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
153
|
+
}
|
|
154
|
+
function renderCallbackHtml(success) {
|
|
155
|
+
return `<!doctype html><html><head><meta charset="utf-8"><title>Orizm CLI</title></head><body><p>${success ? "Login successful. You can close this tab and return to the terminal." : "Login failed. You can close this tab and return to the terminal."}</p></body></html>`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
//#endregion
|
|
159
|
+
//#region src/cli/commands/auth/login.ts
|
|
160
|
+
var login_default = require_cli_main.defineCommand({
|
|
161
|
+
meta: {
|
|
162
|
+
name: "login",
|
|
163
|
+
description: "Sign in to Orizm"
|
|
164
|
+
},
|
|
165
|
+
args: { ...require_shared.globalArgs },
|
|
166
|
+
run: async () => {
|
|
167
|
+
const env = require_token_store.resolveEnv();
|
|
168
|
+
if (_praha_byethrow.Result.isFailure(env)) return _praha_byethrow.Result.fail({ message: "Invalid Orizm environment configuration." });
|
|
169
|
+
const { issuerUrl } = env.value;
|
|
170
|
+
require_cli_main.notice("Opening your browser to complete sign-in. Finish within 5 minutes...");
|
|
171
|
+
const result = await authorize({
|
|
172
|
+
issuerUrl,
|
|
173
|
+
onAuthorizationUrl: (url) => require_cli_main.notice(`Could not open a browser automatically. Open this URL:\n${url}`)
|
|
174
|
+
});
|
|
175
|
+
if (_praha_byethrow.Result.isFailure(result)) return authorizeFailure(result.error);
|
|
176
|
+
const { tokenSet, claims } = result.value;
|
|
177
|
+
await new require_token_store.FileTokenStore().set(issuerUrl, {
|
|
178
|
+
accessToken: tokenSet.accessToken,
|
|
179
|
+
refreshToken: tokenSet.refreshToken,
|
|
180
|
+
idToken: tokenSet.idToken,
|
|
181
|
+
expiresAt: tokenSet.expiresAt,
|
|
182
|
+
scope: tokenSet.scope,
|
|
183
|
+
subject: claims.subject,
|
|
184
|
+
profile: {
|
|
185
|
+
name: claims.name,
|
|
186
|
+
email: claims.email
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
const who = claims.email ?? claims.name ?? claims.subject;
|
|
190
|
+
return _praha_byethrow.Result.succeed({
|
|
191
|
+
json: {
|
|
192
|
+
issuer: issuerUrl,
|
|
193
|
+
subject: claims.subject,
|
|
194
|
+
email: claims.email
|
|
195
|
+
},
|
|
196
|
+
text: () => `Logged in as ${who}.`
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
function authorizeFailure(error) {
|
|
201
|
+
switch (error.type) {
|
|
202
|
+
case "callback_server_failed": return _praha_byethrow.Result.fail({ message: "Could not start the local sign-in listener. Check that your environment allows local connections, then try again." });
|
|
203
|
+
case "callback_timeout": return _praha_byethrow.Result.fail({ message: "Timed out before the browser sign-in completed. Run `orizm auth login` again." });
|
|
204
|
+
case "state_mismatch": return _praha_byethrow.Result.fail({ message: "Sign-in failed due to a security check. Please try again." });
|
|
205
|
+
case "user_denied": return _praha_byethrow.Result.fail({ message: "Sign-in was denied." });
|
|
206
|
+
case "token_exchange_failed": return _praha_byethrow.Result.fail({ message: `Sign-in failed: ${error.reason}. Please try again.` });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
//#endregion
|
|
211
|
+
exports.default = login_default;
|
|
212
|
+
//# sourceMappingURL=login-2XcHd4wn.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login-2XcHd4wn.cjs","names":["Hono","Result","buildAuthorizationUrl","openBrowser","exchangeCode","verifyIdToken","defineCommand","globalArgs","resolveEnv","Result","notice","FileTokenStore"],"sources":["../src/cli/util/base64url.ts","../src/cli/util/random.ts","../src/cli/util/sha256.ts","../src/cli/auth/pkce.ts","../src/cli/auth/state.ts","../src/cli/auth/authorize.ts","../src/cli/commands/auth/login.ts"],"sourcesContent":["// Node 固有の Buffer ではなく Web 標準の btoa/atob を使う。特定ランタイムの API に\n// 縛られず、ブラウザ / Deno / Edge でもそのまま動く形にしておくため。\nexport function encodeBase64Url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return globalThis\n .btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport function decodeBase64Url(text: string): Uint8Array {\n const base64 = text.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = globalThis.atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n","export function randomBytes(length: number): Uint8Array {\n return globalThis.crypto.getRandomValues(new Uint8Array(length));\n}\n","export async function sha256(data: Uint8Array): Promise<Uint8Array> {\n // 新しい TS lib は Uint8Array を ArrayBufferLike でジェネリックにし digest が ArrayBuffer 裏付けを要求するため、\n // ArrayBuffer 裏付けの view にコピーしてから渡す。\n const view = new Uint8Array(data);\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", view);\n return new Uint8Array(digest);\n}\n","import { encodeBase64Url } from \"../util/base64url.js\";\nimport { randomBytes } from \"../util/random.js\";\nimport { sha256 } from \"../util/sha256.js\";\n\nexport type Pkce = {\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: \"S256\";\n};\n\nexport async function createPkce(): Promise<Pkce> {\n const codeVerifier = encodeBase64Url(randomBytes(32));\n const digest = await sha256(new TextEncoder().encode(codeVerifier));\n return {\n codeVerifier,\n codeChallenge: encodeBase64Url(digest),\n codeChallengeMethod: \"S256\",\n };\n}\n","import { encodeBase64Url } from \"../util/base64url.js\";\nimport { randomBytes } from \"../util/random.js\";\n\nexport function createState(): string {\n return encodeBase64Url(randomBytes(32));\n}\n\nexport function verifyState(\n expected: string,\n received: string | null,\n): boolean {\n return received !== null && received === expected;\n}\n","import { serve, type ServerType } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport openBrowser from \"open\";\nimport { Result } from \"@praha/byethrow\";\nimport { createPkce } from \"./pkce.js\";\nimport { createState, verifyState } from \"./state.js\";\nimport {\n buildAuthorizationUrl,\n exchangeCode,\n verifyIdToken,\n type IdTokenClaims,\n type TokenExchangeError,\n type TokenSet,\n} from \"./oauth-client.js\";\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport type AuthorizeError =\n | { type: \"callback_server_failed\" }\n | { type: \"callback_timeout\" }\n | { type: \"state_mismatch\" }\n | { type: \"user_denied\"; description?: string }\n | TokenExchangeError;\n\nexport type AuthorizeSuccess = {\n issuerUrl: string;\n tokenSet: TokenSet;\n claims: IdTokenClaims;\n};\n\ntype CallbackQuery = {\n code?: string;\n state?: string;\n error?: string;\n errorDescription?: string;\n};\n\nexport type AuthorizeParams = {\n issuerUrl: string;\n // ブラウザ起動を差し替え可能にして統合テストで「ブラウザ役」の fetch を流せるようにする。\n openBrowser?: (url: string) => Promise<void>;\n // ブラウザ起動に失敗したときに authorization URL を利用者へ手動提示するための通知口。\n onAuthorizationUrl?: (url: string) => void;\n timeoutMs?: number;\n};\n\nexport async function authorize(\n params: AuthorizeParams,\n): Promise<Result.Result<AuthorizeSuccess, AuthorizeError>> {\n const { issuerUrl } = params;\n const pkce = await createPkce();\n const state = createState();\n\n let resolveCallback: (query: CallbackQuery) => void = () => {};\n const callbackReceived = new Promise<CallbackQuery>((resolve) => {\n resolveCallback = resolve;\n });\n\n const app = new Hono();\n app.get(\"/callback\", (c) => {\n const query = c.req.query();\n resolveCallback({\n code: query.code,\n state: query.state,\n error: query.error,\n errorDescription: query.error_description,\n });\n return c.html(renderCallbackHtml(query.error == null));\n });\n\n let listened: { server: ServerType; port: number };\n try {\n listened = await listen(app);\n } catch {\n // loopback に bind できない環境ではログインを完遂できないため、待たずに失敗を返す。\n return Result.fail({ type: \"callback_server_failed\" });\n }\n const { server, port } = listened;\n\n try {\n const redirectUri = `http://127.0.0.1:${port}/callback`;\n const authorizationUrl = buildAuthorizationUrl({\n issuerUrl,\n redirectUri,\n codeChallenge: pkce.codeChallenge,\n codeChallengeMethod: pkce.codeChallengeMethod,\n state,\n });\n\n const openImpl = params.openBrowser ?? openBrowser;\n await openImpl(authorizationUrl).catch(() => {\n params.onAuthorizationUrl?.(authorizationUrl);\n });\n\n const query = await waitForCallback(\n callbackReceived,\n params.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n );\n if (query == null) {\n return Result.fail({ type: \"callback_timeout\" });\n }\n\n // 成功・失敗どちらの応答も Authorization Server は state を返すため、分岐する前に検証する。\n // 無関係なローカルリクエスト(?error=... 等)で進行中のログインを中断させないため。\n if (!verifyState(state, query.state ?? null)) {\n return Result.fail({ type: \"state_mismatch\" });\n }\n\n if (query.error != null) {\n if (query.error === \"access_denied\") {\n return Result.fail({\n type: \"user_denied\",\n description: query.errorDescription,\n });\n }\n return Result.fail({\n type: \"token_exchange_failed\",\n reason: [query.error, query.errorDescription]\n .filter((part) => part != null)\n .join(\": \"),\n });\n }\n\n if (query.code == null) {\n return Result.fail({\n type: \"token_exchange_failed\",\n reason: \"Authorization response did not include a code\",\n });\n }\n\n const exchanged = await exchangeCode({\n issuerUrl,\n code: query.code,\n redirectUri,\n codeVerifier: pkce.codeVerifier,\n });\n if (Result.isFailure(exchanged)) return exchanged;\n\n const claims = await verifyIdToken(issuerUrl, exchanged.value.idToken);\n\n return Result.succeed({ issuerUrl, tokenSet: exchanged.value, claims });\n } finally {\n await closeServer(server);\n }\n}\n\nasync function listen(\n app: Hono,\n): Promise<{ server: ServerType; port: number }> {\n return new Promise((resolve, reject) => {\n const server = serve(\n { fetch: app.fetch, hostname: \"127.0.0.1\", port: 0 },\n (info) => resolve({ server, port: info.port }),\n );\n server.on(\"error\", (error) => reject(error));\n });\n}\n\nasync function waitForCallback(\n callbackReceived: Promise<CallbackQuery>,\n timeoutMs: number,\n): Promise<CallbackQuery | undefined> {\n let timer: NodeJS.Timeout | undefined;\n const timedOut = new Promise<undefined>((resolve) => {\n timer = setTimeout(() => resolve(undefined), timeoutMs);\n });\n try {\n return await Promise.race([callbackReceived, timedOut]);\n } finally {\n if (timer != null) clearTimeout(timer);\n }\n}\n\nasync function closeServer(server: ServerType): Promise<void> {\n await new Promise<void>((resolve) => server.close(() => resolve()));\n}\n\nfunction renderCallbackHtml(success: boolean): string {\n const message = success\n ? \"Login successful. You can close this tab and return to the terminal.\"\n : \"Login failed. You can close this tab and return to the terminal.\";\n return `<!doctype html><html><head><meta charset=\"utf-8\"><title>Orizm CLI</title></head><body><p>${message}</p></body></html>`;\n}\n","import { Result } from \"@praha/byethrow\";\nimport { defineCommand } from \"../define-command.js\";\nimport { globalArgs } from \"../shared.js\";\nimport { CommandFailure } from \"../define-command.js\";\nimport { resolveEnv } from \"../../env.js\";\nimport { authorize, type AuthorizeError } from \"../../auth/authorize.js\";\nimport { FileTokenStore } from \"../../auth/token-store.js\";\nimport { notice } from \"../../ui/output.js\";\n\nexport default defineCommand({\n meta: {\n name: \"login\",\n description: \"Sign in to Orizm\",\n },\n args: { ...globalArgs },\n run: async () => {\n const env = resolveEnv();\n if (Result.isFailure(env)) {\n return Result.fail({\n message: \"Invalid Orizm environment configuration.\",\n });\n }\n const { issuerUrl } = env.value;\n\n notice(\n \"Opening your browser to complete sign-in. Finish within 5 minutes...\",\n );\n\n const result = await authorize({\n issuerUrl,\n onAuthorizationUrl: (url) =>\n notice(\n `Could not open a browser automatically. Open this URL:\\n${url}`,\n ),\n });\n if (Result.isFailure(result)) {\n return authorizeFailure(result.error);\n }\n\n const { tokenSet, claims } = result.value;\n await new FileTokenStore().set(issuerUrl, {\n accessToken: tokenSet.accessToken,\n refreshToken: tokenSet.refreshToken,\n idToken: tokenSet.idToken,\n expiresAt: tokenSet.expiresAt,\n scope: tokenSet.scope,\n subject: claims.subject,\n profile: { name: claims.name, email: claims.email },\n });\n\n const who = claims.email ?? claims.name ?? claims.subject;\n return Result.succeed({\n json: { issuer: issuerUrl, subject: claims.subject, email: claims.email },\n text: () => `Logged in as ${who}.`,\n });\n },\n});\n\nfunction authorizeFailure(\n error: AuthorizeError,\n): Result.Result<never, CommandFailure> {\n switch (error.type) {\n case \"callback_server_failed\":\n return Result.fail({\n message:\n \"Could not start the local sign-in listener. Check that your environment allows local connections, then try again.\",\n });\n case \"callback_timeout\":\n return Result.fail({\n message:\n \"Timed out before the browser sign-in completed. Run `orizm auth login` again.\",\n });\n case \"state_mismatch\":\n return Result.fail({\n message: \"Sign-in failed due to a security check. Please try again.\",\n });\n case \"user_denied\":\n return Result.fail({ message: \"Sign-in was denied.\" });\n case \"token_exchange_failed\":\n return Result.fail({\n message: `Sign-in failed: ${error.reason}. Please try again.`,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { a as notice, t as defineCommand } from "./cli/main.mjs";
|
|
2
|
+
import { i as globalArgs } from "./shared-CZZimGxc.mjs";
|
|
3
|
+
import { n as resolveEnv, t as FileTokenStore } from "./token-store-reCGF86F.mjs";
|
|
4
|
+
import { a as verifyIdToken, n as exchangeCode, t as buildAuthorizationUrl } from "./oauth-client-QHuDa4fW.mjs";
|
|
5
|
+
import { Result } from "@praha/byethrow";
|
|
6
|
+
import { serve } from "@hono/node-server";
|
|
7
|
+
import { Hono } from "hono";
|
|
8
|
+
import openBrowser from "open";
|
|
9
|
+
|
|
10
|
+
//#region src/cli/util/base64url.ts
|
|
11
|
+
function encodeBase64Url(bytes) {
|
|
12
|
+
let binary = "";
|
|
13
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
14
|
+
return globalThis.btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/cli/util/random.ts
|
|
19
|
+
function randomBytes(length) {
|
|
20
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(length));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/cli/util/sha256.ts
|
|
25
|
+
async function sha256(data) {
|
|
26
|
+
const view = new Uint8Array(data);
|
|
27
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", view);
|
|
28
|
+
return new Uint8Array(digest);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/cli/auth/pkce.ts
|
|
33
|
+
async function createPkce() {
|
|
34
|
+
const codeVerifier = encodeBase64Url(randomBytes(32));
|
|
35
|
+
return {
|
|
36
|
+
codeVerifier,
|
|
37
|
+
codeChallenge: encodeBase64Url(await sha256(new TextEncoder().encode(codeVerifier))),
|
|
38
|
+
codeChallengeMethod: "S256"
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/cli/auth/state.ts
|
|
44
|
+
function createState() {
|
|
45
|
+
return encodeBase64Url(randomBytes(32));
|
|
46
|
+
}
|
|
47
|
+
function verifyState(expected, received) {
|
|
48
|
+
return received !== null && received === expected;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/cli/auth/authorize.ts
|
|
53
|
+
const DEFAULT_TIMEOUT_MS = 300 * 1e3;
|
|
54
|
+
async function authorize(params) {
|
|
55
|
+
const { issuerUrl } = params;
|
|
56
|
+
const pkce = await createPkce();
|
|
57
|
+
const state = createState();
|
|
58
|
+
let resolveCallback = () => {};
|
|
59
|
+
const callbackReceived = new Promise((resolve) => {
|
|
60
|
+
resolveCallback = resolve;
|
|
61
|
+
});
|
|
62
|
+
const app = new Hono();
|
|
63
|
+
app.get("/callback", (c) => {
|
|
64
|
+
const query = c.req.query();
|
|
65
|
+
resolveCallback({
|
|
66
|
+
code: query.code,
|
|
67
|
+
state: query.state,
|
|
68
|
+
error: query.error,
|
|
69
|
+
errorDescription: query.error_description
|
|
70
|
+
});
|
|
71
|
+
return c.html(renderCallbackHtml(query.error == null));
|
|
72
|
+
});
|
|
73
|
+
let listened;
|
|
74
|
+
try {
|
|
75
|
+
listened = await listen(app);
|
|
76
|
+
} catch {
|
|
77
|
+
return Result.fail({ type: "callback_server_failed" });
|
|
78
|
+
}
|
|
79
|
+
const { server, port } = listened;
|
|
80
|
+
try {
|
|
81
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
82
|
+
const authorizationUrl = buildAuthorizationUrl({
|
|
83
|
+
issuerUrl,
|
|
84
|
+
redirectUri,
|
|
85
|
+
codeChallenge: pkce.codeChallenge,
|
|
86
|
+
codeChallengeMethod: pkce.codeChallengeMethod,
|
|
87
|
+
state
|
|
88
|
+
});
|
|
89
|
+
await (params.openBrowser ?? openBrowser)(authorizationUrl).catch(() => {
|
|
90
|
+
params.onAuthorizationUrl?.(authorizationUrl);
|
|
91
|
+
});
|
|
92
|
+
const query = await waitForCallback(callbackReceived, params.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
93
|
+
if (query == null) return Result.fail({ type: "callback_timeout" });
|
|
94
|
+
if (!verifyState(state, query.state ?? null)) return Result.fail({ type: "state_mismatch" });
|
|
95
|
+
if (query.error != null) {
|
|
96
|
+
if (query.error === "access_denied") return Result.fail({
|
|
97
|
+
type: "user_denied",
|
|
98
|
+
description: query.errorDescription
|
|
99
|
+
});
|
|
100
|
+
return Result.fail({
|
|
101
|
+
type: "token_exchange_failed",
|
|
102
|
+
reason: [query.error, query.errorDescription].filter((part) => part != null).join(": ")
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (query.code == null) return Result.fail({
|
|
106
|
+
type: "token_exchange_failed",
|
|
107
|
+
reason: "Authorization response did not include a code"
|
|
108
|
+
});
|
|
109
|
+
const exchanged = await exchangeCode({
|
|
110
|
+
issuerUrl,
|
|
111
|
+
code: query.code,
|
|
112
|
+
redirectUri,
|
|
113
|
+
codeVerifier: pkce.codeVerifier
|
|
114
|
+
});
|
|
115
|
+
if (Result.isFailure(exchanged)) return exchanged;
|
|
116
|
+
const claims = await verifyIdToken(issuerUrl, exchanged.value.idToken);
|
|
117
|
+
return Result.succeed({
|
|
118
|
+
issuerUrl,
|
|
119
|
+
tokenSet: exchanged.value,
|
|
120
|
+
claims
|
|
121
|
+
});
|
|
122
|
+
} finally {
|
|
123
|
+
await closeServer(server);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async function listen(app) {
|
|
127
|
+
return new Promise((resolve, reject) => {
|
|
128
|
+
const server = serve({
|
|
129
|
+
fetch: app.fetch,
|
|
130
|
+
hostname: "127.0.0.1",
|
|
131
|
+
port: 0
|
|
132
|
+
}, (info) => resolve({
|
|
133
|
+
server,
|
|
134
|
+
port: info.port
|
|
135
|
+
}));
|
|
136
|
+
server.on("error", (error) => reject(error));
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
async function waitForCallback(callbackReceived, timeoutMs) {
|
|
140
|
+
let timer;
|
|
141
|
+
const timedOut = new Promise((resolve) => {
|
|
142
|
+
timer = setTimeout(() => resolve(void 0), timeoutMs);
|
|
143
|
+
});
|
|
144
|
+
try {
|
|
145
|
+
return await Promise.race([callbackReceived, timedOut]);
|
|
146
|
+
} finally {
|
|
147
|
+
if (timer != null) clearTimeout(timer);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function closeServer(server) {
|
|
151
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
152
|
+
}
|
|
153
|
+
function renderCallbackHtml(success) {
|
|
154
|
+
return `<!doctype html><html><head><meta charset="utf-8"><title>Orizm CLI</title></head><body><p>${success ? "Login successful. You can close this tab and return to the terminal." : "Login failed. You can close this tab and return to the terminal."}</p></body></html>`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/cli/commands/auth/login.ts
|
|
159
|
+
var login_default = defineCommand({
|
|
160
|
+
meta: {
|
|
161
|
+
name: "login",
|
|
162
|
+
description: "Sign in to Orizm"
|
|
163
|
+
},
|
|
164
|
+
args: { ...globalArgs },
|
|
165
|
+
run: async () => {
|
|
166
|
+
const env = resolveEnv();
|
|
167
|
+
if (Result.isFailure(env)) return Result.fail({ message: "Invalid Orizm environment configuration." });
|
|
168
|
+
const { issuerUrl } = env.value;
|
|
169
|
+
notice("Opening your browser to complete sign-in. Finish within 5 minutes...");
|
|
170
|
+
const result = await authorize({
|
|
171
|
+
issuerUrl,
|
|
172
|
+
onAuthorizationUrl: (url) => notice(`Could not open a browser automatically. Open this URL:\n${url}`)
|
|
173
|
+
});
|
|
174
|
+
if (Result.isFailure(result)) return authorizeFailure(result.error);
|
|
175
|
+
const { tokenSet, claims } = result.value;
|
|
176
|
+
await new FileTokenStore().set(issuerUrl, {
|
|
177
|
+
accessToken: tokenSet.accessToken,
|
|
178
|
+
refreshToken: tokenSet.refreshToken,
|
|
179
|
+
idToken: tokenSet.idToken,
|
|
180
|
+
expiresAt: tokenSet.expiresAt,
|
|
181
|
+
scope: tokenSet.scope,
|
|
182
|
+
subject: claims.subject,
|
|
183
|
+
profile: {
|
|
184
|
+
name: claims.name,
|
|
185
|
+
email: claims.email
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
const who = claims.email ?? claims.name ?? claims.subject;
|
|
189
|
+
return Result.succeed({
|
|
190
|
+
json: {
|
|
191
|
+
issuer: issuerUrl,
|
|
192
|
+
subject: claims.subject,
|
|
193
|
+
email: claims.email
|
|
194
|
+
},
|
|
195
|
+
text: () => `Logged in as ${who}.`
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
function authorizeFailure(error) {
|
|
200
|
+
switch (error.type) {
|
|
201
|
+
case "callback_server_failed": return Result.fail({ message: "Could not start the local sign-in listener. Check that your environment allows local connections, then try again." });
|
|
202
|
+
case "callback_timeout": return Result.fail({ message: "Timed out before the browser sign-in completed. Run `orizm auth login` again." });
|
|
203
|
+
case "state_mismatch": return Result.fail({ message: "Sign-in failed due to a security check. Please try again." });
|
|
204
|
+
case "user_denied": return Result.fail({ message: "Sign-in was denied." });
|
|
205
|
+
case "token_exchange_failed": return Result.fail({ message: `Sign-in failed: ${error.reason}. Please try again.` });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
//#endregion
|
|
210
|
+
export { login_default as default };
|
|
211
|
+
//# sourceMappingURL=login-FE_dbWMo.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login-FE_dbWMo.mjs","names":[],"sources":["../src/cli/util/base64url.ts","../src/cli/util/random.ts","../src/cli/util/sha256.ts","../src/cli/auth/pkce.ts","../src/cli/auth/state.ts","../src/cli/auth/authorize.ts","../src/cli/commands/auth/login.ts"],"sourcesContent":["// Node 固有の Buffer ではなく Web 標準の btoa/atob を使う。特定ランタイムの API に\n// 縛られず、ブラウザ / Deno / Edge でもそのまま動く形にしておくため。\nexport function encodeBase64Url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return globalThis\n .btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport function decodeBase64Url(text: string): Uint8Array {\n const base64 = text.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = globalThis.atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n","export function randomBytes(length: number): Uint8Array {\n return globalThis.crypto.getRandomValues(new Uint8Array(length));\n}\n","export async function sha256(data: Uint8Array): Promise<Uint8Array> {\n // 新しい TS lib は Uint8Array を ArrayBufferLike でジェネリックにし digest が ArrayBuffer 裏付けを要求するため、\n // ArrayBuffer 裏付けの view にコピーしてから渡す。\n const view = new Uint8Array(data);\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", view);\n return new Uint8Array(digest);\n}\n","import { encodeBase64Url } from \"../util/base64url.js\";\nimport { randomBytes } from \"../util/random.js\";\nimport { sha256 } from \"../util/sha256.js\";\n\nexport type Pkce = {\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: \"S256\";\n};\n\nexport async function createPkce(): Promise<Pkce> {\n const codeVerifier = encodeBase64Url(randomBytes(32));\n const digest = await sha256(new TextEncoder().encode(codeVerifier));\n return {\n codeVerifier,\n codeChallenge: encodeBase64Url(digest),\n codeChallengeMethod: \"S256\",\n };\n}\n","import { encodeBase64Url } from \"../util/base64url.js\";\nimport { randomBytes } from \"../util/random.js\";\n\nexport function createState(): string {\n return encodeBase64Url(randomBytes(32));\n}\n\nexport function verifyState(\n expected: string,\n received: string | null,\n): boolean {\n return received !== null && received === expected;\n}\n","import { serve, type ServerType } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport openBrowser from \"open\";\nimport { Result } from \"@praha/byethrow\";\nimport { createPkce } from \"./pkce.js\";\nimport { createState, verifyState } from \"./state.js\";\nimport {\n buildAuthorizationUrl,\n exchangeCode,\n verifyIdToken,\n type IdTokenClaims,\n type TokenExchangeError,\n type TokenSet,\n} from \"./oauth-client.js\";\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport type AuthorizeError =\n | { type: \"callback_server_failed\" }\n | { type: \"callback_timeout\" }\n | { type: \"state_mismatch\" }\n | { type: \"user_denied\"; description?: string }\n | TokenExchangeError;\n\nexport type AuthorizeSuccess = {\n issuerUrl: string;\n tokenSet: TokenSet;\n claims: IdTokenClaims;\n};\n\ntype CallbackQuery = {\n code?: string;\n state?: string;\n error?: string;\n errorDescription?: string;\n};\n\nexport type AuthorizeParams = {\n issuerUrl: string;\n // ブラウザ起動を差し替え可能にして統合テストで「ブラウザ役」の fetch を流せるようにする。\n openBrowser?: (url: string) => Promise<void>;\n // ブラウザ起動に失敗したときに authorization URL を利用者へ手動提示するための通知口。\n onAuthorizationUrl?: (url: string) => void;\n timeoutMs?: number;\n};\n\nexport async function authorize(\n params: AuthorizeParams,\n): Promise<Result.Result<AuthorizeSuccess, AuthorizeError>> {\n const { issuerUrl } = params;\n const pkce = await createPkce();\n const state = createState();\n\n let resolveCallback: (query: CallbackQuery) => void = () => {};\n const callbackReceived = new Promise<CallbackQuery>((resolve) => {\n resolveCallback = resolve;\n });\n\n const app = new Hono();\n app.get(\"/callback\", (c) => {\n const query = c.req.query();\n resolveCallback({\n code: query.code,\n state: query.state,\n error: query.error,\n errorDescription: query.error_description,\n });\n return c.html(renderCallbackHtml(query.error == null));\n });\n\n let listened: { server: ServerType; port: number };\n try {\n listened = await listen(app);\n } catch {\n // loopback に bind できない環境ではログインを完遂できないため、待たずに失敗を返す。\n return Result.fail({ type: \"callback_server_failed\" });\n }\n const { server, port } = listened;\n\n try {\n const redirectUri = `http://127.0.0.1:${port}/callback`;\n const authorizationUrl = buildAuthorizationUrl({\n issuerUrl,\n redirectUri,\n codeChallenge: pkce.codeChallenge,\n codeChallengeMethod: pkce.codeChallengeMethod,\n state,\n });\n\n const openImpl = params.openBrowser ?? openBrowser;\n await openImpl(authorizationUrl).catch(() => {\n params.onAuthorizationUrl?.(authorizationUrl);\n });\n\n const query = await waitForCallback(\n callbackReceived,\n params.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n );\n if (query == null) {\n return Result.fail({ type: \"callback_timeout\" });\n }\n\n // 成功・失敗どちらの応答も Authorization Server は state を返すため、分岐する前に検証する。\n // 無関係なローカルリクエスト(?error=... 等)で進行中のログインを中断させないため。\n if (!verifyState(state, query.state ?? null)) {\n return Result.fail({ type: \"state_mismatch\" });\n }\n\n if (query.error != null) {\n if (query.error === \"access_denied\") {\n return Result.fail({\n type: \"user_denied\",\n description: query.errorDescription,\n });\n }\n return Result.fail({\n type: \"token_exchange_failed\",\n reason: [query.error, query.errorDescription]\n .filter((part) => part != null)\n .join(\": \"),\n });\n }\n\n if (query.code == null) {\n return Result.fail({\n type: \"token_exchange_failed\",\n reason: \"Authorization response did not include a code\",\n });\n }\n\n const exchanged = await exchangeCode({\n issuerUrl,\n code: query.code,\n redirectUri,\n codeVerifier: pkce.codeVerifier,\n });\n if (Result.isFailure(exchanged)) return exchanged;\n\n const claims = await verifyIdToken(issuerUrl, exchanged.value.idToken);\n\n return Result.succeed({ issuerUrl, tokenSet: exchanged.value, claims });\n } finally {\n await closeServer(server);\n }\n}\n\nasync function listen(\n app: Hono,\n): Promise<{ server: ServerType; port: number }> {\n return new Promise((resolve, reject) => {\n const server = serve(\n { fetch: app.fetch, hostname: \"127.0.0.1\", port: 0 },\n (info) => resolve({ server, port: info.port }),\n );\n server.on(\"error\", (error) => reject(error));\n });\n}\n\nasync function waitForCallback(\n callbackReceived: Promise<CallbackQuery>,\n timeoutMs: number,\n): Promise<CallbackQuery | undefined> {\n let timer: NodeJS.Timeout | undefined;\n const timedOut = new Promise<undefined>((resolve) => {\n timer = setTimeout(() => resolve(undefined), timeoutMs);\n });\n try {\n return await Promise.race([callbackReceived, timedOut]);\n } finally {\n if (timer != null) clearTimeout(timer);\n }\n}\n\nasync function closeServer(server: ServerType): Promise<void> {\n await new Promise<void>((resolve) => server.close(() => resolve()));\n}\n\nfunction renderCallbackHtml(success: boolean): string {\n const message = success\n ? \"Login successful. You can close this tab and return to the terminal.\"\n : \"Login failed. You can close this tab and return to the terminal.\";\n return `<!doctype html><html><head><meta charset=\"utf-8\"><title>Orizm CLI</title></head><body><p>${message}</p></body></html>`;\n}\n","import { Result } from \"@praha/byethrow\";\nimport { defineCommand } from \"../define-command.js\";\nimport { globalArgs } from \"../shared.js\";\nimport { CommandFailure } from \"../define-command.js\";\nimport { resolveEnv } from \"../../env.js\";\nimport { authorize, type AuthorizeError } from \"../../auth/authorize.js\";\nimport { FileTokenStore } from \"../../auth/token-store.js\";\nimport { notice } from \"../../ui/output.js\";\n\nexport default defineCommand({\n meta: {\n name: \"login\",\n description: \"Sign in to Orizm\",\n },\n args: { ...globalArgs },\n run: async () => {\n const env = resolveEnv();\n if (Result.isFailure(env)) {\n return Result.fail({\n message: \"Invalid Orizm environment configuration.\",\n });\n }\n const { issuerUrl } = env.value;\n\n notice(\n \"Opening your browser to complete sign-in. Finish within 5 minutes...\",\n );\n\n const result = await authorize({\n issuerUrl,\n onAuthorizationUrl: (url) =>\n notice(\n `Could not open a browser automatically. Open this URL:\\n${url}`,\n ),\n });\n if (Result.isFailure(result)) {\n return authorizeFailure(result.error);\n }\n\n const { tokenSet, claims } = result.value;\n await new FileTokenStore().set(issuerUrl, {\n accessToken: tokenSet.accessToken,\n refreshToken: tokenSet.refreshToken,\n idToken: tokenSet.idToken,\n expiresAt: tokenSet.expiresAt,\n scope: tokenSet.scope,\n subject: claims.subject,\n profile: { name: claims.name, email: claims.email },\n });\n\n const who = claims.email ?? claims.name ?? claims.subject;\n return Result.succeed({\n json: { issuer: issuerUrl, subject: claims.subject, email: claims.email },\n text: () => `Logged in as ${who}.`,\n });\n },\n});\n\nfunction authorizeFailure(\n error: AuthorizeError,\n): Result.Result<never, CommandFailure> {\n switch (error.type) {\n case \"callback_server_failed\":\n return Result.fail({\n message:\n \"Could not start the local sign-in listener. Check that your environment allows local connections, then try again.\",\n });\n case \"callback_timeout\":\n return Result.fail({\n message:\n \"Timed out before the browser sign-in completed. Run `orizm auth login` again.\",\n });\n case \"state_mismatch\":\n return Result.fail({\n message: \"Sign-in failed due to a security check. Please try again.\",\n });\n case \"user_denied\":\n return Result.fail({ message: \"Sign-in was denied.\" });\n case \"token_exchange_failed\":\n return Result.fail({\n message: `Sign-in failed: ${error.reason}. Please try again.`,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { t as defineCommand } from "./cli/main.mjs";
|
|
2
|
+
import { i as globalArgs } from "./shared-CZZimGxc.mjs";
|
|
3
|
+
import { n as resolveEnv, t as FileTokenStore } from "./token-store-reCGF86F.mjs";
|
|
4
|
+
import { i as revokeToken } from "./oauth-client-QHuDa4fW.mjs";
|
|
5
|
+
import { Result } from "@praha/byethrow";
|
|
6
|
+
|
|
7
|
+
//#region src/cli/commands/auth/logout.ts
|
|
8
|
+
var logout_default = defineCommand({
|
|
9
|
+
meta: {
|
|
10
|
+
name: "logout",
|
|
11
|
+
description: "Sign out of Orizm"
|
|
12
|
+
},
|
|
13
|
+
args: { ...globalArgs },
|
|
14
|
+
run: async () => {
|
|
15
|
+
const env = resolveEnv();
|
|
16
|
+
if (Result.isFailure(env)) return Result.fail({ message: "Invalid Orizm environment configuration." });
|
|
17
|
+
const { issuerUrl } = env.value;
|
|
18
|
+
const store = new FileTokenStore();
|
|
19
|
+
const entry = await store.get(issuerUrl);
|
|
20
|
+
if (entry === void 0) return Result.succeed({
|
|
21
|
+
json: { loggedOut: false },
|
|
22
|
+
text: () => "You are not logged in."
|
|
23
|
+
});
|
|
24
|
+
await revokeToken(issuerUrl, entry.refreshToken).catch(() => void 0);
|
|
25
|
+
await store.remove(issuerUrl);
|
|
26
|
+
return Result.succeed({
|
|
27
|
+
json: { loggedOut: true },
|
|
28
|
+
text: () => "Logged out."
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { logout_default as default };
|
|
35
|
+
//# sourceMappingURL=logout-BDbWrGBm.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout-BDbWrGBm.mjs","names":[],"sources":["../src/cli/commands/auth/logout.ts"],"sourcesContent":["import { Result } from \"@praha/byethrow\";\nimport { defineCommand } from \"../define-command.js\";\nimport { globalArgs } from \"../shared.js\";\nimport { resolveEnv } from \"../../env.js\";\nimport { FileTokenStore } from \"../../auth/token-store.js\";\nimport { revokeToken } from \"../../auth/oauth-client.js\";\n\nexport default defineCommand({\n meta: {\n name: \"logout\",\n description: \"Sign out of Orizm\",\n },\n args: { ...globalArgs },\n run: async () => {\n const env = resolveEnv();\n if (Result.isFailure(env)) {\n return Result.fail({\n message: \"Invalid Orizm environment configuration.\",\n });\n }\n const { issuerUrl } = env.value;\n\n const store = new FileTokenStore();\n const entry = await store.get(issuerUrl);\n if (entry === undefined) {\n return Result.succeed({\n json: { loggedOut: false },\n text: () => \"You are not logged in.\",\n });\n }\n\n // Hydra 側 revoke は best-effort。失敗してもローカル破棄でログアウトは成立させる。\n await revokeToken(issuerUrl, entry.refreshToken).catch(() => undefined);\n await store.remove(issuerUrl);\n\n return Result.succeed({\n json: { loggedOut: true },\n text: () => \"Logged out.\",\n });\n },\n});\n"],"mappings":";;;;;;;AAOA,qBAAe,cAAc;CAC3B,MAAM;EACJ,MAAM;EACN,aAAa;CACf;CACA,MAAM,EAAE,GAAG,WAAW;CACtB,KAAK,YAAY;EACf,MAAM,MAAM,WAAW;EACvB,IAAI,OAAO,UAAU,GAAG,GACtB,OAAO,OAAO,KAAK,EACjB,SAAS,2CACX,CAAC;EAEH,MAAM,EAAE,cAAc,IAAI;EAE1B,MAAM,QAAQ,IAAI,eAAe;EACjC,MAAM,QAAQ,MAAM,MAAM,IAAI,SAAS;EACvC,IAAI,UAAU,QACZ,OAAO,OAAO,QAAQ;GACpB,MAAM,EAAE,WAAW,MAAM;GACzB,YAAY;EACd,CAAC;EAIH,MAAM,YAAY,WAAW,MAAM,YAAY,CAAC,CAAC,YAAY,MAAS;EACtE,MAAM,MAAM,OAAO,SAAS;EAE5B,OAAO,OAAO,QAAQ;GACpB,MAAM,EAAE,WAAW,KAAK;GACxB,YAAY;EACd,CAAC;CACH;AACF,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const require_cli_main = require('./cli/main.cjs');
|
|
2
|
+
const require_shared = require('./shared-DHRPzzKl.cjs');
|
|
3
|
+
const require_token_store = require('./token-store--9GYVL7N.cjs');
|
|
4
|
+
const require_oauth_client = require('./oauth-client-CdD0evAV.cjs');
|
|
5
|
+
let _praha_byethrow = require("@praha/byethrow");
|
|
6
|
+
|
|
7
|
+
//#region src/cli/commands/auth/logout.ts
|
|
8
|
+
var logout_default = require_cli_main.defineCommand({
|
|
9
|
+
meta: {
|
|
10
|
+
name: "logout",
|
|
11
|
+
description: "Sign out of Orizm"
|
|
12
|
+
},
|
|
13
|
+
args: { ...require_shared.globalArgs },
|
|
14
|
+
run: async () => {
|
|
15
|
+
const env = require_token_store.resolveEnv();
|
|
16
|
+
if (_praha_byethrow.Result.isFailure(env)) return _praha_byethrow.Result.fail({ message: "Invalid Orizm environment configuration." });
|
|
17
|
+
const { issuerUrl } = env.value;
|
|
18
|
+
const store = new require_token_store.FileTokenStore();
|
|
19
|
+
const entry = await store.get(issuerUrl);
|
|
20
|
+
if (entry === void 0) return _praha_byethrow.Result.succeed({
|
|
21
|
+
json: { loggedOut: false },
|
|
22
|
+
text: () => "You are not logged in."
|
|
23
|
+
});
|
|
24
|
+
await require_oauth_client.revokeToken(issuerUrl, entry.refreshToken).catch(() => void 0);
|
|
25
|
+
await store.remove(issuerUrl);
|
|
26
|
+
return _praha_byethrow.Result.succeed({
|
|
27
|
+
json: { loggedOut: true },
|
|
28
|
+
text: () => "Logged out."
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
exports.default = logout_default;
|
|
35
|
+
//# sourceMappingURL=logout-DC5TMJ5_.cjs.map
|