@ttctl/cli 0.0.0 → 0.1.0-rc.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 +44 -9
- package/dist/commands/applications/index.d.ts +21 -0
- package/dist/commands/applications/index.d.ts.map +1 -0
- package/dist/commands/applications/index.js +87 -0
- package/dist/commands/applications/index.js.map +1 -0
- package/dist/commands/applications/list.d.ts +55 -0
- package/dist/commands/applications/list.d.ts.map +1 -0
- package/dist/commands/applications/list.js +106 -0
- package/dist/commands/applications/list.js.map +1 -0
- package/dist/commands/applications/shared.d.ts +14 -0
- package/dist/commands/applications/shared.d.ts.map +1 -0
- package/dist/commands/applications/shared.js +19 -0
- package/dist/commands/applications/shared.js.map +1 -0
- package/dist/commands/applications/show.d.ts +51 -0
- package/dist/commands/applications/show.d.ts.map +1 -0
- package/dist/commands/applications/show.js +154 -0
- package/dist/commands/applications/show.js.map +1 -0
- package/dist/commands/applications/stats.d.ts +42 -0
- package/dist/commands/applications/stats.d.ts.map +1 -0
- package/dist/commands/applications/stats.js +69 -0
- package/dist/commands/applications/stats.js.map +1 -0
- package/dist/commands/auth/index.d.ts +17 -0
- package/dist/commands/auth/index.d.ts.map +1 -0
- package/dist/commands/auth/index.js +69 -0
- package/dist/commands/auth/index.js.map +1 -0
- package/dist/commands/auth/init.d.ts +98 -0
- package/dist/commands/auth/init.d.ts.map +1 -0
- package/dist/commands/auth/init.js +387 -0
- package/dist/commands/auth/init.js.map +1 -0
- package/dist/commands/auth/signin.d.ts +81 -0
- package/dist/commands/auth/signin.d.ts.map +1 -0
- package/dist/commands/auth/signin.js +145 -0
- package/dist/commands/auth/signin.js.map +1 -0
- package/dist/commands/auth/signout.d.ts +133 -0
- package/dist/commands/auth/signout.d.ts.map +1 -0
- package/dist/commands/auth/signout.js +172 -0
- package/dist/commands/auth/signout.js.map +1 -0
- package/dist/commands/auth/status.d.ts +62 -0
- package/dist/commands/auth/status.d.ts.map +1 -0
- package/dist/commands/auth/status.js +98 -0
- package/dist/commands/auth/status.js.map +1 -0
- package/dist/commands/availability/allocated-hours.d.ts +27 -0
- package/dist/commands/availability/allocated-hours.d.ts.map +1 -0
- package/dist/commands/availability/allocated-hours.js +61 -0
- package/dist/commands/availability/allocated-hours.js.map +1 -0
- package/dist/commands/availability/index.d.ts +30 -0
- package/dist/commands/availability/index.d.ts.map +1 -0
- package/dist/commands/availability/index.js +124 -0
- package/dist/commands/availability/index.js.map +1 -0
- package/dist/commands/availability/shared.d.ts +11 -0
- package/dist/commands/availability/shared.d.ts.map +1 -0
- package/dist/commands/availability/shared.js +30 -0
- package/dist/commands/availability/shared.js.map +1 -0
- package/dist/commands/availability/show.d.ts +32 -0
- package/dist/commands/availability/show.d.ts.map +1 -0
- package/dist/commands/availability/show.js +86 -0
- package/dist/commands/availability/show.js.map +1 -0
- package/dist/commands/availability/working-hours.d.ts +53 -0
- package/dist/commands/availability/working-hours.d.ts.map +1 -0
- package/dist/commands/availability/working-hours.js +151 -0
- package/dist/commands/availability/working-hours.js.map +1 -0
- package/dist/commands/contracts/index.d.ts +69 -0
- package/dist/commands/contracts/index.d.ts.map +1 -0
- package/dist/commands/contracts/index.js +198 -0
- package/dist/commands/contracts/index.js.map +1 -0
- package/dist/commands/engagements/breaks.d.ts +81 -0
- package/dist/commands/engagements/breaks.d.ts.map +1 -0
- package/dist/commands/engagements/breaks.js +229 -0
- package/dist/commands/engagements/breaks.js.map +1 -0
- package/dist/commands/engagements/index.d.ts +29 -0
- package/dist/commands/engagements/index.d.ts.map +1 -0
- package/dist/commands/engagements/index.js +172 -0
- package/dist/commands/engagements/index.js.map +1 -0
- package/dist/commands/engagements/list.d.ts +49 -0
- package/dist/commands/engagements/list.d.ts.map +1 -0
- package/dist/commands/engagements/list.js +95 -0
- package/dist/commands/engagements/list.js.map +1 -0
- package/dist/commands/engagements/shared.d.ts +10 -0
- package/dist/commands/engagements/shared.d.ts.map +1 -0
- package/dist/commands/engagements/shared.js +31 -0
- package/dist/commands/engagements/shared.js.map +1 -0
- package/dist/commands/engagements/show.d.ts +19 -0
- package/dist/commands/engagements/show.d.ts.map +1 -0
- package/dist/commands/engagements/show.js +150 -0
- package/dist/commands/engagements/show.js.map +1 -0
- package/dist/commands/engagements/stats.d.ts +24 -0
- package/dist/commands/engagements/stats.d.ts.map +1 -0
- package/dist/commands/engagements/stats.js +51 -0
- package/dist/commands/engagements/stats.js.map +1 -0
- package/dist/commands/jobs/index.d.ts +49 -0
- package/dist/commands/jobs/index.d.ts.map +1 -0
- package/dist/commands/jobs/index.js +304 -0
- package/dist/commands/jobs/index.js.map +1 -0
- package/dist/commands/jobs/interest.d.ts +65 -0
- package/dist/commands/jobs/interest.d.ts.map +1 -0
- package/dist/commands/jobs/interest.js +172 -0
- package/dist/commands/jobs/interest.js.map +1 -0
- package/dist/commands/jobs/list.d.ts +81 -0
- package/dist/commands/jobs/list.d.ts.map +1 -0
- package/dist/commands/jobs/list.js +157 -0
- package/dist/commands/jobs/list.js.map +1 -0
- package/dist/commands/jobs/search.d.ts +71 -0
- package/dist/commands/jobs/search.d.ts.map +1 -0
- package/dist/commands/jobs/search.js +163 -0
- package/dist/commands/jobs/search.js.map +1 -0
- package/dist/commands/jobs/shared.d.ts +79 -0
- package/dist/commands/jobs/shared.d.ts.map +1 -0
- package/dist/commands/jobs/shared.js +133 -0
- package/dist/commands/jobs/shared.js.map +1 -0
- package/dist/commands/jobs/show.d.ts +20 -0
- package/dist/commands/jobs/show.d.ts.map +1 -0
- package/dist/commands/jobs/show.js +135 -0
- package/dist/commands/jobs/show.js.map +1 -0
- package/dist/commands/payments/index.d.ts +34 -0
- package/dist/commands/payments/index.d.ts.map +1 -0
- package/dist/commands/payments/index.js +160 -0
- package/dist/commands/payments/index.js.map +1 -0
- package/dist/commands/payments/methods.d.ts +17 -0
- package/dist/commands/payments/methods.d.ts.map +1 -0
- package/dist/commands/payments/methods.js +79 -0
- package/dist/commands/payments/methods.js.map +1 -0
- package/dist/commands/payments/payouts.d.ts +44 -0
- package/dist/commands/payments/payouts.d.ts.map +1 -0
- package/dist/commands/payments/payouts.js +147 -0
- package/dist/commands/payments/payouts.js.map +1 -0
- package/dist/commands/payments/rate.d.ts +48 -0
- package/dist/commands/payments/rate.d.ts.map +1 -0
- package/dist/commands/payments/rate.js +229 -0
- package/dist/commands/payments/rate.js.map +1 -0
- package/dist/commands/payments/shared.d.ts +10 -0
- package/dist/commands/payments/shared.d.ts.map +1 -0
- package/dist/commands/payments/shared.js +27 -0
- package/dist/commands/payments/shared.js.map +1 -0
- package/dist/commands/profile/basic/index.d.ts +18 -0
- package/dist/commands/profile/basic/index.d.ts.map +1 -0
- package/dist/commands/profile/basic/index.js +79 -0
- package/dist/commands/profile/basic/index.js.map +1 -0
- package/dist/commands/profile/basic/photo-show.d.ts +28 -0
- package/dist/commands/profile/basic/photo-show.d.ts.map +1 -0
- package/dist/commands/profile/basic/photo-show.js +112 -0
- package/dist/commands/profile/basic/photo-show.js.map +1 -0
- package/dist/commands/profile/basic/photo-upload.d.ts +10 -0
- package/dist/commands/profile/basic/photo-upload.d.ts.map +1 -0
- package/dist/commands/profile/basic/photo-upload.js +61 -0
- package/dist/commands/profile/basic/photo-upload.js.map +1 -0
- package/dist/commands/profile/basic/set.d.ts +54 -0
- package/dist/commands/profile/basic/set.d.ts.map +1 -0
- package/dist/commands/profile/basic/set.js +174 -0
- package/dist/commands/profile/basic/set.js.map +1 -0
- package/dist/commands/profile/basic/show.d.ts +95 -0
- package/dist/commands/profile/basic/show.d.ts.map +1 -0
- package/dist/commands/profile/basic/show.js +310 -0
- package/dist/commands/profile/basic/show.js.map +1 -0
- package/dist/commands/profile/certifications/index.d.ts +31 -0
- package/dist/commands/profile/certifications/index.d.ts.map +1 -0
- package/dist/commands/profile/certifications/index.js +298 -0
- package/dist/commands/profile/certifications/index.js.map +1 -0
- package/dist/commands/profile/education/index.d.ts +28 -0
- package/dist/commands/profile/education/index.d.ts.map +1 -0
- package/dist/commands/profile/education/index.js +287 -0
- package/dist/commands/profile/education/index.js.map +1 -0
- package/dist/commands/profile/employment/index.d.ts +40 -0
- package/dist/commands/profile/employment/index.d.ts.map +1 -0
- package/dist/commands/profile/employment/index.js +364 -0
- package/dist/commands/profile/employment/index.js.map +1 -0
- package/dist/commands/profile/external/_shared.d.ts +35 -0
- package/dist/commands/profile/external/_shared.d.ts.map +1 -0
- package/dist/commands/profile/external/_shared.js +59 -0
- package/dist/commands/profile/external/_shared.js.map +1 -0
- package/dist/commands/profile/external/advanced-wizard-show.d.ts +15 -0
- package/dist/commands/profile/external/advanced-wizard-show.d.ts.map +1 -0
- package/dist/commands/profile/external/advanced-wizard-show.js +82 -0
- package/dist/commands/profile/external/advanced-wizard-show.js.map +1 -0
- package/dist/commands/profile/external/custom-requirements-set.d.ts +32 -0
- package/dist/commands/profile/external/custom-requirements-set.d.ts.map +1 -0
- package/dist/commands/profile/external/custom-requirements-set.js +116 -0
- package/dist/commands/profile/external/custom-requirements-set.js.map +1 -0
- package/dist/commands/profile/external/custom-requirements-show.d.ts +16 -0
- package/dist/commands/profile/external/custom-requirements-show.d.ts.map +1 -0
- package/dist/commands/profile/external/custom-requirements-show.js +84 -0
- package/dist/commands/profile/external/custom-requirements-show.js.map +1 -0
- package/dist/commands/profile/external/index.d.ts +20 -0
- package/dist/commands/profile/external/index.d.ts.map +1 -0
- package/dist/commands/profile/external/index.js +102 -0
- package/dist/commands/profile/external/index.js.map +1 -0
- package/dist/commands/profile/external/readiness.d.ts +15 -0
- package/dist/commands/profile/external/readiness.d.ts.map +1 -0
- package/dist/commands/profile/external/readiness.js +104 -0
- package/dist/commands/profile/external/readiness.js.map +1 -0
- package/dist/commands/profile/external/recommendations.d.ts +17 -0
- package/dist/commands/profile/external/recommendations.d.ts.map +1 -0
- package/dist/commands/profile/external/recommendations.js +97 -0
- package/dist/commands/profile/external/recommendations.js.map +1 -0
- package/dist/commands/profile/external/update.d.ts +32 -0
- package/dist/commands/profile/external/update.d.ts.map +1 -0
- package/dist/commands/profile/external/update.js +118 -0
- package/dist/commands/profile/external/update.js.map +1 -0
- package/dist/commands/profile/index.d.ts +16 -0
- package/dist/commands/profile/index.d.ts.map +1 -0
- package/dist/commands/profile/index.js +81 -0
- package/dist/commands/profile/index.js.map +1 -0
- package/dist/commands/profile/industries/index.d.ts +36 -0
- package/dist/commands/profile/industries/index.d.ts.map +1 -0
- package/dist/commands/profile/industries/index.js +230 -0
- package/dist/commands/profile/industries/index.js.map +1 -0
- package/dist/commands/profile/portfolio/add.d.ts +43 -0
- package/dist/commands/profile/portfolio/add.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/add.js +181 -0
- package/dist/commands/profile/portfolio/add.js.map +1 -0
- package/dist/commands/profile/portfolio/highlight.d.ts +11 -0
- package/dist/commands/profile/portfolio/highlight.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/highlight.js +31 -0
- package/dist/commands/profile/portfolio/highlight.js.map +1 -0
- package/dist/commands/profile/portfolio/index.d.ts +16 -0
- package/dist/commands/profile/portfolio/index.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/index.js +121 -0
- package/dist/commands/profile/portfolio/index.js.map +1 -0
- package/dist/commands/profile/portfolio/list.d.ts +83 -0
- package/dist/commands/profile/portfolio/list.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/list.js +189 -0
- package/dist/commands/profile/portfolio/list.js.map +1 -0
- package/dist/commands/profile/portfolio/remove.d.ts +9 -0
- package/dist/commands/profile/portfolio/remove.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/remove.js +24 -0
- package/dist/commands/profile/portfolio/remove.js.map +1 -0
- package/dist/commands/profile/portfolio/reorder.d.ts +17 -0
- package/dist/commands/profile/portfolio/reorder.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/reorder.js +135 -0
- package/dist/commands/profile/portfolio/reorder.js.map +1 -0
- package/dist/commands/profile/portfolio/shared.d.ts +8 -0
- package/dist/commands/profile/portfolio/shared.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/shared.js +10 -0
- package/dist/commands/profile/portfolio/shared.js.map +1 -0
- package/dist/commands/profile/portfolio/update.d.ts +18 -0
- package/dist/commands/profile/portfolio/update.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/update.js +77 -0
- package/dist/commands/profile/portfolio/update.js.map +1 -0
- package/dist/commands/profile/portfolio/upload.d.ts +8 -0
- package/dist/commands/profile/portfolio/upload.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/upload.js +131 -0
- package/dist/commands/profile/portfolio/upload.js.map +1 -0
- package/dist/commands/profile/resume/cancel-upload.d.ts +9 -0
- package/dist/commands/profile/resume/cancel-upload.d.ts.map +1 -0
- package/dist/commands/profile/resume/cancel-upload.js +30 -0
- package/dist/commands/profile/resume/cancel-upload.js.map +1 -0
- package/dist/commands/profile/resume/index.d.ts +15 -0
- package/dist/commands/profile/resume/index.d.ts.map +1 -0
- package/dist/commands/profile/resume/index.js +42 -0
- package/dist/commands/profile/resume/index.js.map +1 -0
- package/dist/commands/profile/resume/upload.d.ts +16 -0
- package/dist/commands/profile/resume/upload.d.ts.map +1 -0
- package/dist/commands/profile/resume/upload.js +65 -0
- package/dist/commands/profile/resume/upload.js.map +1 -0
- package/dist/commands/profile/reviews/_shared.d.ts +9 -0
- package/dist/commands/profile/reviews/_shared.d.ts.map +1 -0
- package/dist/commands/profile/reviews/_shared.js +15 -0
- package/dist/commands/profile/reviews/_shared.js.map +1 -0
- package/dist/commands/profile/reviews/approve-item.d.ts +30 -0
- package/dist/commands/profile/reviews/approve-item.d.ts.map +1 -0
- package/dist/commands/profile/reviews/approve-item.js +82 -0
- package/dist/commands/profile/reviews/approve-item.js.map +1 -0
- package/dist/commands/profile/reviews/approve-section.d.ts +15 -0
- package/dist/commands/profile/reviews/approve-section.d.ts.map +1 -0
- package/dist/commands/profile/reviews/approve-section.js +67 -0
- package/dist/commands/profile/reviews/approve-section.js.map +1 -0
- package/dist/commands/profile/reviews/index.d.ts +19 -0
- package/dist/commands/profile/reviews/index.d.ts.map +1 -0
- package/dist/commands/profile/reviews/index.js +71 -0
- package/dist/commands/profile/reviews/index.js.map +1 -0
- package/dist/commands/profile/reviews/list.d.ts +17 -0
- package/dist/commands/profile/reviews/list.d.ts.map +1 -0
- package/dist/commands/profile/reviews/list.js +96 -0
- package/dist/commands/profile/reviews/list.js.map +1 -0
- package/dist/commands/profile/reviews/submit-for-review.d.ts +16 -0
- package/dist/commands/profile/reviews/submit-for-review.d.ts.map +1 -0
- package/dist/commands/profile/reviews/submit-for-review.js +65 -0
- package/dist/commands/profile/reviews/submit-for-review.js.map +1 -0
- package/dist/commands/profile/shared.d.ts +46 -0
- package/dist/commands/profile/shared.d.ts.map +1 -0
- package/dist/commands/profile/shared.js +111 -0
- package/dist/commands/profile/shared.js.map +1 -0
- package/dist/commands/profile/skills/index.d.ts +29 -0
- package/dist/commands/profile/skills/index.d.ts.map +1 -0
- package/dist/commands/profile/skills/index.js +475 -0
- package/dist/commands/profile/skills/index.js.map +1 -0
- package/dist/commands/profile/visas/add.d.ts +19 -0
- package/dist/commands/profile/visas/add.d.ts.map +1 -0
- package/dist/commands/profile/visas/add.js +37 -0
- package/dist/commands/profile/visas/add.js.map +1 -0
- package/dist/commands/profile/visas/index.d.ts +13 -0
- package/dist/commands/profile/visas/index.d.ts.map +1 -0
- package/dist/commands/profile/visas/index.js +69 -0
- package/dist/commands/profile/visas/index.js.map +1 -0
- package/dist/commands/profile/visas/list.d.ts +40 -0
- package/dist/commands/profile/visas/list.d.ts.map +1 -0
- package/dist/commands/profile/visas/list.js +115 -0
- package/dist/commands/profile/visas/list.js.map +1 -0
- package/dist/commands/profile/visas/remove.d.ts +8 -0
- package/dist/commands/profile/visas/remove.d.ts.map +1 -0
- package/dist/commands/profile/visas/remove.js +23 -0
- package/dist/commands/profile/visas/remove.js.map +1 -0
- package/dist/commands/profile/visas/shared.d.ts +11 -0
- package/dist/commands/profile/visas/shared.d.ts.map +1 -0
- package/dist/commands/profile/visas/shared.js +16 -0
- package/dist/commands/profile/visas/shared.js.map +1 -0
- package/dist/commands/profile/visas/update.d.ts +13 -0
- package/dist/commands/profile/visas/update.d.ts.map +1 -0
- package/dist/commands/profile/visas/update.js +44 -0
- package/dist/commands/profile/visas/update.js.map +1 -0
- package/dist/commands/timesheet/index.d.ts +24 -0
- package/dist/commands/timesheet/index.d.ts.map +1 -0
- package/dist/commands/timesheet/index.js +98 -0
- package/dist/commands/timesheet/index.js.map +1 -0
- package/dist/commands/timesheet/list.d.ts +40 -0
- package/dist/commands/timesheet/list.d.ts.map +1 -0
- package/dist/commands/timesheet/list.js +79 -0
- package/dist/commands/timesheet/list.js.map +1 -0
- package/dist/commands/timesheet/shared.d.ts +10 -0
- package/dist/commands/timesheet/shared.d.ts.map +1 -0
- package/dist/commands/timesheet/shared.js +35 -0
- package/dist/commands/timesheet/shared.js.map +1 -0
- package/dist/commands/timesheet/show.d.ts +19 -0
- package/dist/commands/timesheet/show.d.ts.map +1 -0
- package/dist/commands/timesheet/show.js +109 -0
- package/dist/commands/timesheet/show.js.map +1 -0
- package/dist/commands/timesheet/submit.d.ts +50 -0
- package/dist/commands/timesheet/submit.d.ts.map +1 -0
- package/dist/commands/timesheet/submit.js +151 -0
- package/dist/commands/timesheet/submit.js.map +1 -0
- package/dist/crash-handlers.d.ts +67 -0
- package/dist/crash-handlers.d.ts.map +1 -0
- package/dist/crash-handlers.js +78 -0
- package/dist/crash-handlers.js.map +1 -0
- package/dist/errors.d.ts +45 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +57 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config-context.d.ts +41 -0
- package/dist/lib/config-context.d.ts.map +1 -0
- package/dist/lib/config-context.js +74 -0
- package/dist/lib/config-context.js.map +1 -0
- package/dist/lib/dry-run.d.ts +70 -0
- package/dist/lib/dry-run.d.ts.map +1 -0
- package/dist/lib/dry-run.js +114 -0
- package/dist/lib/dry-run.js.map +1 -0
- package/dist/lib/empty-state-cta.d.ts +63 -0
- package/dist/lib/empty-state-cta.d.ts.map +1 -0
- package/dist/lib/empty-state-cta.js +88 -0
- package/dist/lib/empty-state-cta.js.map +1 -0
- package/dist/lib/envelopes.d.ts +540 -0
- package/dist/lib/envelopes.d.ts.map +1 -0
- package/dist/lib/envelopes.js +598 -0
- package/dist/lib/envelopes.js.map +1 -0
- package/dist/lib/error-routing.d.ts +49 -0
- package/dist/lib/error-routing.d.ts.map +1 -0
- package/dist/lib/error-routing.js +72 -0
- package/dist/lib/error-routing.js.map +1 -0
- package/dist/lib/format-helpers.d.ts +65 -0
- package/dist/lib/format-helpers.d.ts.map +1 -0
- package/dist/lib/format-helpers.js +79 -0
- package/dist/lib/format-helpers.js.map +1 -0
- package/dist/lib/format-overrides.d.ts +81 -0
- package/dist/lib/format-overrides.d.ts.map +1 -0
- package/dist/lib/format-overrides.js +55 -0
- package/dist/lib/format-overrides.js.map +1 -0
- package/dist/lib/freetext.d.ts +83 -0
- package/dist/lib/freetext.d.ts.map +1 -0
- package/dist/lib/freetext.js +182 -0
- package/dist/lib/freetext.js.map +1 -0
- package/dist/lib/kill-switch-hook.d.ts +49 -0
- package/dist/lib/kill-switch-hook.d.ts.map +1 -0
- package/dist/lib/kill-switch-hook.js +34 -0
- package/dist/lib/kill-switch-hook.js.map +1 -0
- package/dist/lib/output.d.ts +173 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +177 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/pagination.d.ts +49 -0
- package/dist/lib/pagination.d.ts.map +1 -0
- package/dist/lib/pagination.js +36 -0
- package/dist/lib/pagination.js.map +1 -0
- package/dist/program.d.ts +80 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +273 -0
- package/dist/program.js.map +1 -0
- package/package.json +35 -13
- package/index.js +0 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/commands/timesheet/shared.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,YAAoB,EAAE,GAAY,EAAE,SAAuB,QAAQ;IACtG,iBAAiB,CAAC,YAAY,EAAE,GAAG,EAAE,SAAS,CAAC,cAAc,EAAE,MAAM,EAAE,oBAAoB,CAAC,CAAC;AAC/F,CAAC;AAED;;;GAGG;AACH,SAAS,oBAAoB,CAAC,IAAkC;IAC9D,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,WAAW;YACd,OAAO,2EAA2E,CAAC;QACrF,KAAK,eAAe;YAClB,OAAO,kGAAkG,CAAC;QAC5G,KAAK,kBAAkB;YACrB,OAAO,2GAA2G,CAAC;QACrH,KAAK,yBAAyB;YAC5B,OAAO,2IAA2I,CAAC;QACrJ,KAAK,gBAAgB;YACnB,OAAO,6JAA6J,CAAC;QACvK;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { timesheet } from "@ttctl/core";
|
|
2
|
+
import type { OutputFormat } from "../../lib/output.js";
|
|
3
|
+
/**
|
|
4
|
+
* Action handler for `ttctl timesheet show <id>`. `<id>` is the
|
|
5
|
+
* BillingCycle.id from `ttctl timesheet list`.
|
|
6
|
+
*
|
|
7
|
+
* Pretty rendering is a multi-line key:value layout grouped into
|
|
8
|
+
* sections (Header, Engagement, Submission, Agreement, Records). Empty
|
|
9
|
+
* sections are omitted. `json` / `yaml` always emit the full server
|
|
10
|
+
* payload (including `timesheetUrl`, `actualAgreement`, the full
|
|
11
|
+
* records array, etc.).
|
|
12
|
+
*/
|
|
13
|
+
export declare function runTimesheetShow(id: string, output: OutputFormat): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Render the timesheet detail as a sectioned multi-line block. Pure —
|
|
16
|
+
* directly unit-testable.
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatTimesheetDetail(item: timesheet.TimesheetDetail): string;
|
|
19
|
+
//# sourceMappingURL=show.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../../src/commands/timesheet/show.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAatF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,CAAC,eAAe,GAAG,MAAM,CAgF7E"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { timesheet } from "@ttctl/core";
|
|
4
|
+
import { emitResult } from "../../lib/output.js";
|
|
5
|
+
import { handleTimesheetError, loadAuthTokenOrExit } from "./shared.js";
|
|
6
|
+
/**
|
|
7
|
+
* Action handler for `ttctl timesheet show <id>`. `<id>` is the
|
|
8
|
+
* BillingCycle.id from `ttctl timesheet list`.
|
|
9
|
+
*
|
|
10
|
+
* Pretty rendering is a multi-line key:value layout grouped into
|
|
11
|
+
* sections (Header, Engagement, Submission, Agreement, Records). Empty
|
|
12
|
+
* sections are omitted. `json` / `yaml` always emit the full server
|
|
13
|
+
* payload (including `timesheetUrl`, `actualAgreement`, the full
|
|
14
|
+
* records array, etc.).
|
|
15
|
+
*/
|
|
16
|
+
export async function runTimesheetShow(id, output) {
|
|
17
|
+
const token = await loadAuthTokenOrExit("timesheet show", output);
|
|
18
|
+
let item;
|
|
19
|
+
try {
|
|
20
|
+
item = await timesheet.show(token, id);
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
handleTimesheetError("timesheet show", err, output);
|
|
24
|
+
}
|
|
25
|
+
emitResult(item, output, {
|
|
26
|
+
pretty: (data) => formatTimesheetDetail(data),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Render the timesheet detail as a sectioned multi-line block. Pure —
|
|
31
|
+
* directly unit-testable.
|
|
32
|
+
*/
|
|
33
|
+
export function formatTimesheetDetail(item) {
|
|
34
|
+
const lines = [];
|
|
35
|
+
lines.push(`Timesheet ${item.id}`);
|
|
36
|
+
lines.push(` Week: ${item.startDate} → ${item.endDate}`);
|
|
37
|
+
lines.push(` Hours: ${item.hours}`);
|
|
38
|
+
lines.push(` Submitted: ${String(item.timesheetSubmitted)}`);
|
|
39
|
+
lines.push(` Overdue: ${String(item.timesheetOverdue)}`);
|
|
40
|
+
if (item.timesheetSubmissionOpenDatetime !== null) {
|
|
41
|
+
lines.push(` Submission opens: ${item.timesheetSubmissionOpenDatetime}`);
|
|
42
|
+
}
|
|
43
|
+
if (item.timesheetSubmissionDeadlineDatetime !== null) {
|
|
44
|
+
lines.push(` Submission deadline: ${item.timesheetSubmissionDeadlineDatetime}`);
|
|
45
|
+
}
|
|
46
|
+
if (item.timesheetUrl !== null) {
|
|
47
|
+
lines.push(` URL: ${item.timesheetUrl}`);
|
|
48
|
+
}
|
|
49
|
+
lines.push("");
|
|
50
|
+
lines.push("Engagement");
|
|
51
|
+
if (item.engagement.job.title !== null)
|
|
52
|
+
lines.push(` ${item.engagement.job.title}`);
|
|
53
|
+
if (item.engagement.job.client?.fullName != null) {
|
|
54
|
+
lines.push(` Client: ${item.engagement.job.client.fullName}`);
|
|
55
|
+
}
|
|
56
|
+
// Note: this is `Engagement.id` (TalentEngagement), NOT `JobActivityItem.id`.
|
|
57
|
+
// The `--engagement <id>` flag on `timesheet list/submit` consumes the
|
|
58
|
+
// `JobActivityItem.id` surfaced by `engagements list`, which is a
|
|
59
|
+
// distinct identifier — we name the field verbosely here so users don't
|
|
60
|
+
// copy-paste this id back into `--engagement` and get a NOT_FOUND.
|
|
61
|
+
lines.push(` TalentEngagement id: ${item.engagement.id}`);
|
|
62
|
+
if (item.engagement.expectedHours !== null) {
|
|
63
|
+
lines.push(` Expected hours: ${item.engagement.expectedHours.toString()}`);
|
|
64
|
+
}
|
|
65
|
+
if (item.minimumCommitment !== null && item.minimumCommitment.applicable) {
|
|
66
|
+
lines.push("");
|
|
67
|
+
lines.push("Minimum commitment");
|
|
68
|
+
if (item.minimumCommitment.minimumHours !== null) {
|
|
69
|
+
lines.push(` Minimum hours: ${item.minimumCommitment.minimumHours.toString()}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (item.actualAgreement !== null) {
|
|
73
|
+
lines.push("");
|
|
74
|
+
lines.push("Agreement");
|
|
75
|
+
if (item.actualAgreement.applicationRate !== null) {
|
|
76
|
+
lines.push(` Application rate: ${item.actualAgreement.applicationRate}`);
|
|
77
|
+
}
|
|
78
|
+
if (item.actualAgreement.talentHourlyRate !== null) {
|
|
79
|
+
lines.push(` Hourly rate: ${item.actualAgreement.talentHourlyRate}`);
|
|
80
|
+
}
|
|
81
|
+
if (item.actualAgreement.marketplaceMargin !== null) {
|
|
82
|
+
lines.push(` Marketplace margin: ${item.actualAgreement.marketplaceMargin}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (item.timesheetComment !== null && item.timesheetComment !== "") {
|
|
86
|
+
lines.push("");
|
|
87
|
+
lines.push("Comment");
|
|
88
|
+
for (const para of item.timesheetComment.split(/\n+/)) {
|
|
89
|
+
if (para.trim().length > 0)
|
|
90
|
+
lines.push(` ${para}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (item.timesheetRecords.length > 0) {
|
|
94
|
+
lines.push("");
|
|
95
|
+
lines.push(`Records (${item.timesheetRecords.length.toString()})`);
|
|
96
|
+
for (const rec of item.timesheetRecords) {
|
|
97
|
+
// `duration` is a string-encoded decimal in minutes (e.g., "480.0"
|
|
98
|
+
// for an 8-hour day). `Number()` parses "480.0" → 480; division by
|
|
99
|
+
// 60 yields hours. Pre-#???: this divided by 3600 assuming
|
|
100
|
+
// number-typed seconds, rendering 8h as 0.13h.
|
|
101
|
+
const hours = (Number(rec.duration) / 60).toFixed(2);
|
|
102
|
+
const tag = rec.isDayOff ? " [day off]" : "";
|
|
103
|
+
const note = rec.note != null && rec.note !== "" ? ` — ${rec.note}` : "";
|
|
104
|
+
lines.push(` ${rec.date}: ${hours}h${tag}${note}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return lines.join("\n");
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=show.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/commands/timesheet/show.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { OutputFormat } from "../../lib/output.js";
|
|
2
|
+
/**
|
|
3
|
+
* Action handler for `ttctl timesheet submit [id]`.
|
|
4
|
+
*
|
|
5
|
+
* Per #13 spec, submit is destructive (one-way on the wire). The
|
|
6
|
+
* action is gated behind one of:
|
|
7
|
+
*
|
|
8
|
+
* - `--confirm` flag (script-safe, no prompt)
|
|
9
|
+
* - Interactive TTY confirm via `@clack/prompts` (non-TTY without
|
|
10
|
+
* `--confirm` refuses with a clear error envelope)
|
|
11
|
+
*
|
|
12
|
+
* `<id>` is a positional BillingCycle.id. When omitted, the runner
|
|
13
|
+
* calls {@link timesheet.resolveCurrentCycle} to auto-resolve the
|
|
14
|
+
* single cycle whose submission window contains "now". Optional
|
|
15
|
+
* `--engagement <id>` scopes the resolve to one engagement (uses the
|
|
16
|
+
* `JobActivityItem.id` from `engagements list`).
|
|
17
|
+
*
|
|
18
|
+
* Auto-resolve outcomes:
|
|
19
|
+
*
|
|
20
|
+
* - `kind: "found"` → proceed to confirm + submit
|
|
21
|
+
* - `kind: "none"` → error envelope with code `NO_CURRENT_CYCLE`
|
|
22
|
+
* - `kind: "multiple"` → error envelope with code
|
|
23
|
+
* `MULTIPLE_CURRENT_CYCLES` listing candidate
|
|
24
|
+
* ids in `errors[0].hint` so scripts can
|
|
25
|
+
* disambiguate.
|
|
26
|
+
*
|
|
27
|
+
* Success returns the write-success envelope per #128:
|
|
28
|
+
* `{ok: true, version: "1.0", operation: "timesheet.submit", updated: <detail>}`.
|
|
29
|
+
*
|
|
30
|
+
* Dry-run path: when `getCliDryRun()` is true (the CLI-global
|
|
31
|
+
* `--dry-run` flag was passed), the destructive mutation is replaced
|
|
32
|
+
* by a {@link DryRunPreview}. The confirm gate AND the auto-resolve
|
|
33
|
+
* read are BOTH skipped — auto-resolve uses the placeholder string
|
|
34
|
+
* `<auto-resolved-at-apply-time>` for the id, surfaced via the
|
|
35
|
+
* envelope `notice` so machine consumers don't mistake it for a real
|
|
36
|
+
* cycle id. See {@link DRY_RUN_PLACEHOLDER_NOTICE}.
|
|
37
|
+
*/
|
|
38
|
+
export interface TimesheetSubmitOptions {
|
|
39
|
+
confirm: boolean;
|
|
40
|
+
engagement?: string;
|
|
41
|
+
output: OutputFormat;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Internal seam: `runTimesheetSubmit` decides whether to prompt based
|
|
45
|
+
* on a deterministic predicate. Exported via `isStdinTty` so tests can
|
|
46
|
+
* stub it cleanly without poking `process.stdin.isTTY`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function isStdinTty(): boolean;
|
|
49
|
+
export declare function runTimesheetSubmit(id: string | undefined, opts: TimesheetSubmitOptions): Promise<void>;
|
|
50
|
+
//# sourceMappingURL=submit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../../src/commands/timesheet/submit.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;CACtB;AAYD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+H5G"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import * as p from "@clack/prompts";
|
|
4
|
+
import { timesheet } from "@ttctl/core";
|
|
5
|
+
import { getCliDryRun } from "../../lib/dry-run.js";
|
|
6
|
+
import { emitDryRunSuccess, emitErrorAndExit, emitUpdateSuccess } from "../../lib/envelopes.js";
|
|
7
|
+
import { handleTimesheetError, loadAuthTokenOrExit } from "./shared.js";
|
|
8
|
+
import { formatTimesheetDetail } from "./show.js";
|
|
9
|
+
/**
|
|
10
|
+
* Notice surfaced on the dry-run envelope when the caller omitted the
|
|
11
|
+
* positional `<id>` AND the apply path would have auto-resolved the
|
|
12
|
+
* current cycle. The preview's `variables.id` carries the placeholder
|
|
13
|
+
* string `<auto-resolved-at-apply-time>`; the real BillingCycle.id is
|
|
14
|
+
* resolved at apply time via `PendingTimesheets` (skipped on dry-run).
|
|
15
|
+
*/
|
|
16
|
+
const DRY_RUN_PLACEHOLDER_NOTICE = "id in the preview is the placeholder string `<auto-resolved-at-apply-time>`; the apply path resolves the real BillingCycle.id via a PendingTimesheets query before issuing the mutation — this read is skipped on dry-run.";
|
|
17
|
+
/**
|
|
18
|
+
* Internal seam: `runTimesheetSubmit` decides whether to prompt based
|
|
19
|
+
* on a deterministic predicate. Exported via `isStdinTty` so tests can
|
|
20
|
+
* stub it cleanly without poking `process.stdin.isTTY`.
|
|
21
|
+
*/
|
|
22
|
+
export function isStdinTty() {
|
|
23
|
+
return process.stdin.isTTY === true;
|
|
24
|
+
}
|
|
25
|
+
export async function runTimesheetSubmit(id, opts) {
|
|
26
|
+
const token = await loadAuthTokenOrExit("timesheet submit", opts.output);
|
|
27
|
+
const dryRun = getCliDryRun();
|
|
28
|
+
// Step 1: resolve the cycle id (explicit positional OR auto-resolve).
|
|
29
|
+
// Dry-run path: skip the auto-resolve read entirely and stamp the
|
|
30
|
+
// placeholder. The destructive mutation is never sent.
|
|
31
|
+
let cycleId;
|
|
32
|
+
let usedPlaceholder = false;
|
|
33
|
+
if (id !== undefined) {
|
|
34
|
+
cycleId = id;
|
|
35
|
+
}
|
|
36
|
+
else if (dryRun) {
|
|
37
|
+
cycleId = "<auto-resolved-at-apply-time>";
|
|
38
|
+
usedPlaceholder = true;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const resolveOpts = {};
|
|
42
|
+
if (opts.engagement !== undefined)
|
|
43
|
+
resolveOpts.engagement = opts.engagement;
|
|
44
|
+
let resolution;
|
|
45
|
+
try {
|
|
46
|
+
resolution = await timesheet.resolveCurrentCycle(token, resolveOpts);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
handleTimesheetError("timesheet submit", err, opts.output);
|
|
50
|
+
}
|
|
51
|
+
if (resolution.kind === "none") {
|
|
52
|
+
emitErrorAndExit({
|
|
53
|
+
operation: "timesheet.submit",
|
|
54
|
+
format: opts.output,
|
|
55
|
+
errors: [
|
|
56
|
+
{
|
|
57
|
+
code: "NO_CURRENT_CYCLE",
|
|
58
|
+
message: "No billing cycle is currently in its submission window. Either nothing is due, or every pending cycle is too early / past deadline.",
|
|
59
|
+
hint: "Run `ttctl timesheet list` to see what's pending, or specify a cycle id explicitly.",
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
prettySummary: "timesheet submit failed (NO_CURRENT_CYCLE): no current pending timesheet.",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (resolution.kind === "multiple") {
|
|
66
|
+
const candidateLines = resolution.candidates.map((c) => {
|
|
67
|
+
const client = c.engagement.job.client?.fullName ?? "(no client)";
|
|
68
|
+
const title = c.engagement.job.title ?? "(untitled)";
|
|
69
|
+
return ` - ${c.id} (${client} — ${title}, ${c.startDate} → ${c.endDate})`;
|
|
70
|
+
});
|
|
71
|
+
emitErrorAndExit({
|
|
72
|
+
operation: "timesheet.submit",
|
|
73
|
+
format: opts.output,
|
|
74
|
+
errors: [
|
|
75
|
+
{
|
|
76
|
+
code: "MULTIPLE_CURRENT_CYCLES",
|
|
77
|
+
message: `${resolution.candidates.length.toString()} billing cycles match the current submission window — specify one explicitly.`,
|
|
78
|
+
hint: `Candidates:\n${candidateLines.join("\n")}`,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
prettySummary: `timesheet submit failed (MULTIPLE_CURRENT_CYCLES): ${resolution.candidates.length.toString()} candidates.`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
cycleId = resolution.cycle.id;
|
|
85
|
+
}
|
|
86
|
+
// Step 2: --confirm OR interactive TTY confirm gate.
|
|
87
|
+
// Dry-run path: skip the confirm gate entirely — there's nothing
|
|
88
|
+
// destructive to confirm. The preview is emitted regardless of
|
|
89
|
+
// --confirm / stdin TTY-ness.
|
|
90
|
+
if (!dryRun && !opts.confirm) {
|
|
91
|
+
if (!isStdinTty()) {
|
|
92
|
+
emitErrorAndExit({
|
|
93
|
+
operation: "timesheet.submit",
|
|
94
|
+
format: opts.output,
|
|
95
|
+
errors: [
|
|
96
|
+
{
|
|
97
|
+
code: "CONFIRMATION_REQUIRED",
|
|
98
|
+
message: "timesheet submit is destructive (one-way) and requires explicit confirmation. Pass --confirm or run in an interactive terminal.",
|
|
99
|
+
hint: "Add `--confirm` to the command, or run `ttctl timesheet submit` from a TTY.",
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
prettySummary: "timesheet submit refused: --confirm flag required (non-TTY stdin).",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const proceed = await p.confirm({
|
|
106
|
+
message: `Submit timesheet ${cycleId}? This is one-way and cannot be undone.`,
|
|
107
|
+
initialValue: false,
|
|
108
|
+
});
|
|
109
|
+
if (p.isCancel(proceed) || !proceed) {
|
|
110
|
+
emitErrorAndExit({
|
|
111
|
+
operation: "timesheet.submit",
|
|
112
|
+
format: opts.output,
|
|
113
|
+
errors: [
|
|
114
|
+
{
|
|
115
|
+
code: "CONFIRMATION_DECLINED",
|
|
116
|
+
message: "Submission cancelled by user.",
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
prettySummary: "timesheet submit cancelled by user.",
|
|
120
|
+
exitCode: 1,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Step 3: perform the submission (or build the dry-run preview).
|
|
125
|
+
let outcome;
|
|
126
|
+
try {
|
|
127
|
+
outcome = await timesheet.submit(token, cycleId, { dryRun });
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
handleTimesheetError("timesheet submit", err, opts.output);
|
|
131
|
+
}
|
|
132
|
+
// Step 4: branch on outcome — dry-run preview OR apply-path envelope.
|
|
133
|
+
if (outcome.kind === "preview") {
|
|
134
|
+
emitDryRunSuccess({
|
|
135
|
+
operation: "timesheet.submit",
|
|
136
|
+
format: opts.output,
|
|
137
|
+
preview: outcome.preview,
|
|
138
|
+
...(usedPlaceholder ? { notice: DRY_RUN_PLACEHOLDER_NOTICE } : {}),
|
|
139
|
+
});
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const { result: updated } = outcome;
|
|
143
|
+
emitUpdateSuccess({
|
|
144
|
+
operation: "timesheet.submit",
|
|
145
|
+
format: opts.output,
|
|
146
|
+
updated,
|
|
147
|
+
prettySummary: `timesheet ${updated.id} submitted (${updated.startDate} → ${updated.endDate}, ${updated.hours}h)`,
|
|
148
|
+
prettyEntity: (entity) => formatTimesheetDetail(entity),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=submit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../../../src/commands/timesheet/submit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discriminator for the two top-level crash paths Node.js exposes.
|
|
3
|
+
* `uncaughtException` fires for synchronous throws that escape every
|
|
4
|
+
* try/catch frame; `unhandledRejection` fires for rejected promises with
|
|
5
|
+
* no `.catch()` or `await` upstream. Both are terminal — the process
|
|
6
|
+
* is exiting; the only question is whether the crash output leaks an
|
|
7
|
+
* in-memory secret on the way out.
|
|
8
|
+
*/
|
|
9
|
+
export type CrashKind = "uncaughtException" | "unhandledRejection";
|
|
10
|
+
/**
|
|
11
|
+
* Build the redacted crash log for an uncaught throw or unhandled
|
|
12
|
+
* promise rejection. Returns a multi-line string suitable for stderr.
|
|
13
|
+
*
|
|
14
|
+
* Wire shape:
|
|
15
|
+
*
|
|
16
|
+
* [<kind>] <ErrorName>: <message>
|
|
17
|
+
* <stack>
|
|
18
|
+
*
|
|
19
|
+
* For non-`Error` rejections (`reject("string")`, `reject(42)`,
|
|
20
|
+
* `reject(undefined)`), the name falls back to `UnknownError` and the
|
|
21
|
+
* message is `String(reason)`; there is no stack.
|
|
22
|
+
*
|
|
23
|
+
* **Redaction**: the assembled string is run through {@link redactString}
|
|
24
|
+
* from `@ttctl/core`, replacing every canonical Toptal session bearer
|
|
25
|
+
* (`user_<24hex>_<20alnum>`) with `***REDACTED***`. The crash log
|
|
26
|
+
* intentionally does NOT include `process.env`, command-line arguments,
|
|
27
|
+
* or any other ambient runtime state — those are the load-bearing
|
|
28
|
+
* defenses against process-environment leakage (env vars carrying
|
|
29
|
+
* 1Password session tokens, shell history hints, etc.). Bearer
|
|
30
|
+
* scrubbing is defense-in-depth for the case where a thrown error's
|
|
31
|
+
* message or stack frame interpolates a captured bearer.
|
|
32
|
+
*
|
|
33
|
+
* Pure — no I/O, no process state mutation.
|
|
34
|
+
*
|
|
35
|
+
* See `SECURITY.md` § Crash-output secret invariant for the
|
|
36
|
+
* cross-cutting contract this function satisfies.
|
|
37
|
+
*/
|
|
38
|
+
export declare function formatCrashLog(err: unknown, kind: CrashKind): string;
|
|
39
|
+
/**
|
|
40
|
+
* Install global crash handlers for `uncaughtException` and
|
|
41
|
+
* `unhandledRejection` (issue #207). Each handler:
|
|
42
|
+
*
|
|
43
|
+
* 1. Formats the throw via {@link formatCrashLog} (bearer-pattern
|
|
44
|
+
* scrubbed via `@ttctl/core` `redactString`).
|
|
45
|
+
* 2. Writes the formatted block to `process.stderr` — never `stdout`
|
|
46
|
+
* (the data channel `-o json` / `-o yaml` is owned by command
|
|
47
|
+
* handlers and must remain uncontaminated even on crash).
|
|
48
|
+
* 3. Exits with code `1` (non-zero — generic error).
|
|
49
|
+
*
|
|
50
|
+
* Handlers do NOT log `process.env`, `process.argv`, or any other
|
|
51
|
+
* ambient runtime state; those would risk dumping shell-history hints,
|
|
52
|
+
* 1Password session env vars (`OP_SESSION_*`), and other secrets that
|
|
53
|
+
* tested crash-output assertions cannot catch from the application
|
|
54
|
+
* side.
|
|
55
|
+
*
|
|
56
|
+
* The umbrella bin (`packages/ttctl/src/cli.ts`) calls this once at
|
|
57
|
+
* startup before invoking `main()`. Calling twice would register two
|
|
58
|
+
* listeners for each event — Node.js permits this but it doubles the
|
|
59
|
+
* stderr output, so callers should treat this as a startup-only API.
|
|
60
|
+
*
|
|
61
|
+
* Exit channel: writers use `process.stderr.write` directly rather
|
|
62
|
+
* than `console.error` because the latter can be redirected by
|
|
63
|
+
* downstream test infrastructure in surprising ways. `stderr.write` is
|
|
64
|
+
* the most direct path to the parent process's standard-error stream.
|
|
65
|
+
*/
|
|
66
|
+
export declare function installCrashHandlers(): void;
|
|
67
|
+
//# sourceMappingURL=crash-handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crash-handlers.d.ts","sourceRoot":"","sources":["../src/crash-handlers.ts"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG,mBAAmB,GAAG,oBAAoB,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAQpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAS3C"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { redactString } from "@ttctl/core";
|
|
4
|
+
/**
|
|
5
|
+
* Build the redacted crash log for an uncaught throw or unhandled
|
|
6
|
+
* promise rejection. Returns a multi-line string suitable for stderr.
|
|
7
|
+
*
|
|
8
|
+
* Wire shape:
|
|
9
|
+
*
|
|
10
|
+
* [<kind>] <ErrorName>: <message>
|
|
11
|
+
* <stack>
|
|
12
|
+
*
|
|
13
|
+
* For non-`Error` rejections (`reject("string")`, `reject(42)`,
|
|
14
|
+
* `reject(undefined)`), the name falls back to `UnknownError` and the
|
|
15
|
+
* message is `String(reason)`; there is no stack.
|
|
16
|
+
*
|
|
17
|
+
* **Redaction**: the assembled string is run through {@link redactString}
|
|
18
|
+
* from `@ttctl/core`, replacing every canonical Toptal session bearer
|
|
19
|
+
* (`user_<24hex>_<20alnum>`) with `***REDACTED***`. The crash log
|
|
20
|
+
* intentionally does NOT include `process.env`, command-line arguments,
|
|
21
|
+
* or any other ambient runtime state — those are the load-bearing
|
|
22
|
+
* defenses against process-environment leakage (env vars carrying
|
|
23
|
+
* 1Password session tokens, shell history hints, etc.). Bearer
|
|
24
|
+
* scrubbing is defense-in-depth for the case where a thrown error's
|
|
25
|
+
* message or stack frame interpolates a captured bearer.
|
|
26
|
+
*
|
|
27
|
+
* Pure — no I/O, no process state mutation.
|
|
28
|
+
*
|
|
29
|
+
* See `SECURITY.md` § Crash-output secret invariant for the
|
|
30
|
+
* cross-cutting contract this function satisfies.
|
|
31
|
+
*/
|
|
32
|
+
export function formatCrashLog(err, kind) {
|
|
33
|
+
const isError = err instanceof Error;
|
|
34
|
+
const name = isError ? err.name : "UnknownError";
|
|
35
|
+
const message = isError ? err.message : String(err);
|
|
36
|
+
const stack = isError && err.stack !== undefined && err.stack !== "" ? err.stack : undefined;
|
|
37
|
+
const head = `[${kind}] ${name}: ${message}`;
|
|
38
|
+
const body = stack !== undefined ? `${head}\n${stack}` : head;
|
|
39
|
+
return redactString(body);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Install global crash handlers for `uncaughtException` and
|
|
43
|
+
* `unhandledRejection` (issue #207). Each handler:
|
|
44
|
+
*
|
|
45
|
+
* 1. Formats the throw via {@link formatCrashLog} (bearer-pattern
|
|
46
|
+
* scrubbed via `@ttctl/core` `redactString`).
|
|
47
|
+
* 2. Writes the formatted block to `process.stderr` — never `stdout`
|
|
48
|
+
* (the data channel `-o json` / `-o yaml` is owned by command
|
|
49
|
+
* handlers and must remain uncontaminated even on crash).
|
|
50
|
+
* 3. Exits with code `1` (non-zero — generic error).
|
|
51
|
+
*
|
|
52
|
+
* Handlers do NOT log `process.env`, `process.argv`, or any other
|
|
53
|
+
* ambient runtime state; those would risk dumping shell-history hints,
|
|
54
|
+
* 1Password session env vars (`OP_SESSION_*`), and other secrets that
|
|
55
|
+
* tested crash-output assertions cannot catch from the application
|
|
56
|
+
* side.
|
|
57
|
+
*
|
|
58
|
+
* The umbrella bin (`packages/ttctl/src/cli.ts`) calls this once at
|
|
59
|
+
* startup before invoking `main()`. Calling twice would register two
|
|
60
|
+
* listeners for each event — Node.js permits this but it doubles the
|
|
61
|
+
* stderr output, so callers should treat this as a startup-only API.
|
|
62
|
+
*
|
|
63
|
+
* Exit channel: writers use `process.stderr.write` directly rather
|
|
64
|
+
* than `console.error` because the latter can be redirected by
|
|
65
|
+
* downstream test infrastructure in surprising ways. `stderr.write` is
|
|
66
|
+
* the most direct path to the parent process's standard-error stream.
|
|
67
|
+
*/
|
|
68
|
+
export function installCrashHandlers() {
|
|
69
|
+
process.on("uncaughtException", (err) => {
|
|
70
|
+
process.stderr.write(formatCrashLog(err, "uncaughtException") + "\n");
|
|
71
|
+
process.exit(1);
|
|
72
|
+
});
|
|
73
|
+
process.on("unhandledRejection", (reason) => {
|
|
74
|
+
process.stderr.write(formatCrashLog(reason, "unhandledRejection") + "\n");
|
|
75
|
+
process.exit(1);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=crash-handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crash-handlers.js","sourceRoot":"","sources":["../src/crash-handlers.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAY3C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,cAAc,CAAC,GAAY,EAAE,IAAe;IAC1D,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC;IACrC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC;IACjD,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,OAAO,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7F,MAAM,IAAI,GAAG,IAAI,IAAI,KAAK,IAAI,KAAK,OAAO,EAAE,CAAC;IAC7C,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAU,EAAE,EAAE;QAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,EAAE,mBAAmB,CAAC,GAAG,IAAI,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAe,EAAE,EAAE;QACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAAG,IAAI,CAAC,CAAC;QAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { TtctlError } from "@ttctl/core";
|
|
2
|
+
/**
|
|
3
|
+
* CLI presentation contract for `TtctlError` subclasses (issue #77).
|
|
4
|
+
*
|
|
5
|
+
* The CLI surface renders any `TtctlError` in a uniform multi-block format
|
|
6
|
+
* so users see the same shape whether the failure was an auth revocation,
|
|
7
|
+
* a Cloudflare 403, or a (post-v1) scheduler-bearer expiry:
|
|
8
|
+
*
|
|
9
|
+
* Error: <error.message>
|
|
10
|
+
*
|
|
11
|
+
* Recovery: <error.recovery>
|
|
12
|
+
*
|
|
13
|
+
* (Code: <error.code>)
|
|
14
|
+
*
|
|
15
|
+
* `error.message` may be multi-line (e.g. `Cf403Error.formatMessage`
|
|
16
|
+
* produces a 3-paragraph walkthrough); the renderer passes it through
|
|
17
|
+
* verbatim. `recovery` is one short imperative sentence. `code` is a
|
|
18
|
+
* stable machine-readable token script consumers can branch on without
|
|
19
|
+
* parsing prose.
|
|
20
|
+
*
|
|
21
|
+
* Pure function — no I/O. Callers route the result to `process.stderr` and
|
|
22
|
+
* choose an exit code via `exitCodeForTtctlError`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatTtctlErrorMessage(err: TtctlError): string;
|
|
25
|
+
/**
|
|
26
|
+
* Map a `TtctlError` to a process exit code.
|
|
27
|
+
*
|
|
28
|
+
* Default is `1` (general error — auth revoked, Cloudflare clearance
|
|
29
|
+
* expired, etc.). The 1 / 2 split mirrors the existing `auth status`
|
|
30
|
+
* convention (1 = auth-related, 2 = transient/retryable). `Cf403*` codes
|
|
31
|
+
* map to `2` because they are transport-level blocks the user cannot fix
|
|
32
|
+
* by re-authenticating.
|
|
33
|
+
*/
|
|
34
|
+
export declare function exitCodeForTtctlError(err: TtctlError): number;
|
|
35
|
+
/**
|
|
36
|
+
* Side-effecting renderer: write the formatted block to `process.stderr`
|
|
37
|
+
* and `process.exit` with the corresponding code. Never returns.
|
|
38
|
+
*
|
|
39
|
+
* Command handlers gate this with `instanceof TtctlError` so the uniform
|
|
40
|
+
* presentation only applies to typed-hierarchy errors — other domain
|
|
41
|
+
* errors (`ProfileError`, `SignInError`, …) keep their existing
|
|
42
|
+
* command-specific "(CODE): message" rendering.
|
|
43
|
+
*/
|
|
44
|
+
export declare function presentTtctlError(err: TtctlError): never;
|
|
45
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAE/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAK7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU,GAAG,KAAK,CAGxD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { TtctlError } from "@ttctl/core";
|
|
4
|
+
/**
|
|
5
|
+
* CLI presentation contract for `TtctlError` subclasses (issue #77).
|
|
6
|
+
*
|
|
7
|
+
* The CLI surface renders any `TtctlError` in a uniform multi-block format
|
|
8
|
+
* so users see the same shape whether the failure was an auth revocation,
|
|
9
|
+
* a Cloudflare 403, or a (post-v1) scheduler-bearer expiry:
|
|
10
|
+
*
|
|
11
|
+
* Error: <error.message>
|
|
12
|
+
*
|
|
13
|
+
* Recovery: <error.recovery>
|
|
14
|
+
*
|
|
15
|
+
* (Code: <error.code>)
|
|
16
|
+
*
|
|
17
|
+
* `error.message` may be multi-line (e.g. `Cf403Error.formatMessage`
|
|
18
|
+
* produces a 3-paragraph walkthrough); the renderer passes it through
|
|
19
|
+
* verbatim. `recovery` is one short imperative sentence. `code` is a
|
|
20
|
+
* stable machine-readable token script consumers can branch on without
|
|
21
|
+
* parsing prose.
|
|
22
|
+
*
|
|
23
|
+
* Pure function — no I/O. Callers route the result to `process.stderr` and
|
|
24
|
+
* choose an exit code via `exitCodeForTtctlError`.
|
|
25
|
+
*/
|
|
26
|
+
export function formatTtctlErrorMessage(err) {
|
|
27
|
+
return [`Error: ${err.message}`, "", `Recovery: ${err.recovery}`, "", `(Code: ${err.code})`].join("\n");
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Map a `TtctlError` to a process exit code.
|
|
31
|
+
*
|
|
32
|
+
* Default is `1` (general error — auth revoked, Cloudflare clearance
|
|
33
|
+
* expired, etc.). The 1 / 2 split mirrors the existing `auth status`
|
|
34
|
+
* convention (1 = auth-related, 2 = transient/retryable). `Cf403*` codes
|
|
35
|
+
* map to `2` because they are transport-level blocks the user cannot fix
|
|
36
|
+
* by re-authenticating.
|
|
37
|
+
*/
|
|
38
|
+
export function exitCodeForTtctlError(err) {
|
|
39
|
+
if (err.code === "CF_403_CLEARANCE" || err.code === "CF_403_PERSISTENT") {
|
|
40
|
+
return 2;
|
|
41
|
+
}
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Side-effecting renderer: write the formatted block to `process.stderr`
|
|
46
|
+
* and `process.exit` with the corresponding code. Never returns.
|
|
47
|
+
*
|
|
48
|
+
* Command handlers gate this with `instanceof TtctlError` so the uniform
|
|
49
|
+
* presentation only applies to typed-hierarchy errors — other domain
|
|
50
|
+
* errors (`ProfileError`, `SignInError`, …) keep their existing
|
|
51
|
+
* command-specific "(CODE): message" rendering.
|
|
52
|
+
*/
|
|
53
|
+
export function presentTtctlError(err) {
|
|
54
|
+
process.stderr.write(formatTtctlErrorMessage(err) + "\n");
|
|
55
|
+
process.exit(exitCodeForTtctlError(err));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAe;IACrD,OAAO,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,aAAa,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,UAAU,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1G,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAe;IACnD,IAAI,GAAG,CAAC,IAAI,KAAK,kBAAkB,IAAI,GAAG,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QACxE,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAe;IAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1D,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { buildProgram } from "./program.js";
|
|
2
|
+
export { exitCodeForTtctlError, formatTtctlErrorMessage, presentTtctlError } from "./errors.js";
|
|
3
|
+
export { formatCrashLog, installCrashHandlers } from "./crash-handlers.js";
|
|
4
|
+
export type { CrashKind } from "./crash-handlers.js";
|
|
5
|
+
export { TtctlError } from "@ttctl/core";
|
|
6
|
+
export { ConfigError } from "@ttctl/core";
|
|
7
|
+
export type { ConfigErrorCode } from "@ttctl/core";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3E,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAMzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|