@seliseblocks/cli-os 0.1.3 → 0.1.5
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/AI_USAGE_GUIDE.md +328 -58
- package/README.md +83 -46
- package/dist/commands/auth/client-credentials/delete.d.ts +1 -0
- package/dist/commands/auth/client-credentials/delete.js +23 -0
- package/dist/commands/auth/client-credentials/list.d.ts +1 -0
- package/dist/commands/auth/client-credentials/list.js +14 -0
- package/dist/commands/auth/client-credentials/save.d.ts +1 -0
- package/dist/commands/auth/client-credentials/save.js +41 -0
- package/dist/commands/auth/config/get.d.ts +1 -0
- package/dist/commands/auth/config/get.js +14 -0
- package/dist/commands/auth/config/save.d.ts +1 -0
- package/dist/commands/auth/config/save.js +37 -0
- package/dist/commands/auth/idp/create.d.ts +1 -0
- package/dist/commands/auth/idp/create.js +46 -0
- package/dist/commands/auth/idp/delete.d.ts +1 -0
- package/dist/commands/auth/idp/delete.js +23 -0
- package/dist/commands/auth/idp/get.d.ts +1 -0
- package/dist/commands/auth/idp/get.js +16 -0
- package/dist/commands/auth/idp/list.d.ts +1 -0
- package/dist/commands/auth/idp/list.js +14 -0
- package/dist/commands/auth/idp/status.d.ts +1 -0
- package/dist/commands/auth/idp/status.js +27 -0
- package/dist/commands/auth/idp/update.d.ts +7 -0
- package/dist/commands/auth/idp/update.js +45 -0
- package/dist/commands/auth/oidc-clients/delete.d.ts +1 -0
- package/dist/commands/auth/oidc-clients/delete.js +23 -0
- package/dist/commands/auth/oidc-clients/get.d.ts +1 -0
- package/dist/commands/auth/oidc-clients/get.js +16 -0
- package/dist/commands/auth/oidc-clients/list.d.ts +1 -0
- package/dist/commands/auth/oidc-clients/list.js +14 -0
- package/dist/commands/auth/oidc-clients/rotate-secret.d.ts +1 -0
- package/dist/commands/auth/oidc-clients/rotate-secret.js +23 -0
- package/dist/commands/auth/oidc-clients/save.d.ts +2 -0
- package/dist/commands/auth/oidc-clients/save.js +57 -0
- package/dist/commands/auth/refresh.js +1 -1
- package/dist/commands/data/config/create.d.ts +1 -0
- package/dist/commands/data/config/create.js +38 -0
- package/dist/commands/data/config/get.d.ts +1 -0
- package/dist/commands/data/config/get.js +14 -0
- package/dist/commands/data/config/update.d.ts +1 -0
- package/dist/commands/data/config/update.js +41 -0
- package/dist/commands/data/files/create-folder.d.ts +1 -0
- package/dist/commands/data/files/create-folder.js +34 -0
- package/dist/commands/data/files/delete-folder.d.ts +1 -0
- package/dist/commands/data/files/delete-folder.js +25 -0
- package/dist/commands/data/files/delete.d.ts +1 -0
- package/dist/commands/data/files/delete.js +28 -0
- package/dist/commands/data/files/dms-list.d.ts +1 -0
- package/dist/commands/data/files/dms-list.js +27 -0
- package/dist/commands/data/files/dms-upload.d.ts +6 -0
- package/dist/commands/data/files/dms-upload.js +41 -0
- package/dist/commands/data/files/get-many.d.ts +1 -0
- package/dist/commands/data/files/get-many.js +24 -0
- package/dist/commands/data/files/get.d.ts +1 -0
- package/dist/commands/data/files/get.js +21 -0
- package/dist/commands/data/files/info.d.ts +1 -0
- package/dist/commands/data/files/info.js +30 -0
- package/dist/commands/data/files/presigned-upload-url.d.ts +6 -0
- package/dist/commands/data/files/presigned-upload-url.js +34 -0
- package/dist/commands/data/files/update-additional-info.d.ts +1 -0
- package/dist/commands/data/files/update-additional-info.js +26 -0
- package/dist/commands/data/files/upload-to-local-storage.d.ts +5 -0
- package/dist/commands/data/files/upload-to-local-storage.js +55 -0
- package/dist/commands/data/files/upload-to-url.d.ts +8 -0
- package/dist/commands/data/files/upload-to-url.js +36 -0
- package/dist/commands/data/files/upload.d.ts +7 -0
- package/dist/commands/data/files/upload.js +145 -0
- package/dist/commands/data/rules/policy/delete.d.ts +1 -0
- package/dist/commands/data/rules/policy/delete.js +24 -0
- package/dist/commands/data/rules/policy/get.d.ts +1 -0
- package/dist/commands/data/rules/policy/get.js +17 -0
- package/dist/commands/data/schema/aggregation.d.ts +1 -0
- package/dist/commands/data/schema/aggregation.js +26 -0
- package/dist/commands/data/schema/change-logs.d.ts +1 -0
- package/dist/commands/data/schema/change-logs.js +14 -0
- package/dist/commands/data/schema/delete.d.ts +1 -0
- package/dist/commands/data/schema/delete.js +24 -0
- package/dist/commands/data/schema/fields.d.ts +5 -0
- package/dist/commands/data/schema/fields.js +39 -0
- package/dist/commands/data/schema/get-by-name.d.ts +1 -0
- package/dist/commands/data/schema/get-by-name.js +17 -0
- package/dist/commands/data/schema/get.d.ts +1 -0
- package/dist/commands/data/schema/get.js +17 -0
- package/dist/commands/data/schema/info/list.d.ts +1 -0
- package/dist/commands/data/schema/info/list.js +15 -0
- package/dist/commands/data/schema/info/save.d.ts +1 -0
- package/dist/commands/data/schema/info/save.js +34 -0
- package/dist/commands/data/schema/info/update.d.ts +1 -0
- package/dist/commands/data/schema/info/update.js +35 -0
- package/dist/commands/data/sync.d.ts +7 -0
- package/dist/commands/data/sync.js +46 -0
- package/dist/commands/data/validation/by-schema-field.d.ts +1 -0
- package/dist/commands/data/validation/by-schema-field.js +18 -0
- package/dist/commands/data/validation/by-schema.d.ts +1 -0
- package/dist/commands/data/validation/by-schema.js +17 -0
- package/dist/commands/data/validation/delete.d.ts +1 -0
- package/dist/commands/data/validation/delete.js +24 -0
- package/dist/commands/data/validation/get.d.ts +1 -0
- package/dist/commands/data/validation/get.js +17 -0
- package/dist/commands/data/validation/list.d.ts +1 -0
- package/dist/commands/data/validation/list.js +25 -0
- package/dist/commands/data/validation/save.d.ts +6 -0
- package/dist/commands/data/validation/save.js +44 -0
- package/dist/commands/deselect.d.ts +1 -0
- package/dist/commands/deselect.js +31 -0
- package/dist/commands/iam/email/available.d.ts +1 -0
- package/dist/commands/iam/email/available.js +17 -0
- package/dist/commands/iam/organizations/config-get.d.ts +1 -0
- package/dist/commands/iam/organizations/config-get.js +14 -0
- package/dist/commands/iam/organizations/config-save.d.ts +1 -0
- package/dist/commands/iam/organizations/config-save.js +34 -0
- package/dist/commands/iam/organizations/create.d.ts +1 -0
- package/dist/commands/iam/organizations/create.js +37 -0
- package/dist/commands/iam/organizations/get.d.ts +1 -0
- package/dist/commands/iam/organizations/get.js +16 -0
- package/dist/commands/iam/organizations/list.d.ts +1 -0
- package/dist/commands/iam/organizations/list.js +26 -0
- package/dist/commands/iam/organizations/my.d.ts +1 -0
- package/dist/commands/iam/organizations/my.js +14 -0
- package/dist/commands/iam/organizations/update.d.ts +1 -0
- package/dist/commands/iam/organizations/update.js +39 -0
- package/dist/commands/iam/permissions/by-severity.d.ts +1 -0
- package/dist/commands/iam/permissions/by-severity.js +14 -0
- package/dist/commands/iam/permissions/create.d.ts +1 -0
- package/dist/commands/iam/permissions/create.js +39 -0
- package/dist/commands/iam/permissions/get.d.ts +1 -0
- package/dist/commands/iam/permissions/get.js +16 -0
- package/dist/commands/iam/permissions/list.d.ts +1 -0
- package/dist/commands/iam/permissions/list.js +41 -0
- package/dist/commands/iam/permissions/update.d.ts +1 -0
- package/dist/commands/iam/permissions/update.js +40 -0
- package/dist/commands/iam/resources/features.d.ts +1 -0
- package/dist/commands/iam/resources/features.js +19 -0
- package/dist/commands/iam/resources/groups.d.ts +1 -0
- package/dist/commands/iam/resources/groups.js +14 -0
- package/dist/commands/iam/roles/assign-permissions.d.ts +1 -0
- package/dist/commands/iam/roles/assign-permissions.js +33 -0
- package/dist/commands/iam/roles/assignable.d.ts +1 -0
- package/dist/commands/iam/roles/assignable.js +14 -0
- package/dist/commands/iam/roles/create.d.ts +1 -0
- package/dist/commands/iam/roles/create.js +35 -0
- package/dist/commands/iam/roles/get.d.ts +1 -0
- package/dist/commands/iam/roles/get.js +16 -0
- package/dist/commands/iam/roles/list.d.ts +1 -0
- package/dist/commands/iam/roles/list.js +34 -0
- package/dist/commands/iam/roles/update.d.ts +1 -0
- package/dist/commands/iam/roles/update.js +35 -0
- package/dist/commands/iam/signup-settings/get.d.ts +1 -0
- package/dist/commands/iam/signup-settings/get.js +14 -0
- package/dist/commands/iam/signup-settings/save.d.ts +1 -0
- package/dist/commands/iam/signup-settings/save.js +32 -0
- package/dist/commands/iam/users/access-grant.d.ts +1 -0
- package/dist/commands/iam/users/access-grant.js +32 -0
- package/dist/commands/iam/users/access-revoke.d.ts +1 -0
- package/dist/commands/iam/users/access-revoke.js +24 -0
- package/dist/commands/iam/users/activate.d.ts +1 -0
- package/dist/commands/iam/users/activate.js +24 -0
- package/dist/commands/iam/users/create.d.ts +1 -0
- package/dist/commands/iam/users/create.js +39 -0
- package/dist/commands/iam/users/deactivate.d.ts +1 -0
- package/dist/commands/iam/users/deactivate.js +24 -0
- package/dist/commands/iam/users/exists.d.ts +1 -0
- package/dist/commands/iam/users/exists.js +17 -0
- package/dist/commands/iam/users/get.d.ts +1 -0
- package/dist/commands/iam/users/get.js +17 -0
- package/dist/commands/iam/users/list.d.ts +1 -0
- package/dist/commands/iam/users/list.js +34 -0
- package/dist/commands/iam/users/update.d.ts +1 -0
- package/dist/commands/iam/users/update.js +35 -0
- package/dist/commands/init.js +0 -12
- package/dist/commands/localization/assistant/translation-suggestion.d.ts +1 -0
- package/dist/commands/localization/assistant/translation-suggestion.js +35 -0
- package/dist/commands/localization/config/get-webhook.d.ts +1 -0
- package/dist/commands/localization/config/get-webhook.js +14 -0
- package/dist/commands/localization/config/save-webhook.d.ts +1 -0
- package/dist/commands/localization/config/save-webhook.js +47 -0
- package/dist/commands/localization/glossary/delete.d.ts +1 -0
- package/dist/commands/localization/glossary/delete.js +24 -0
- package/dist/commands/localization/glossary/get.d.ts +1 -0
- package/dist/commands/localization/glossary/get.js +17 -0
- package/dist/commands/localization/glossary/list.d.ts +1 -0
- package/dist/commands/localization/glossary/list.js +22 -0
- package/dist/commands/localization/glossary/save.d.ts +1 -0
- package/dist/commands/localization/glossary/save.js +38 -0
- package/dist/commands/localization/glossary/suggested.d.ts +1 -0
- package/dist/commands/localization/glossary/suggested.js +20 -0
- package/dist/commands/localization/key/delete-keys.d.ts +1 -0
- package/dist/commands/localization/key/delete-keys.js +28 -0
- package/dist/commands/localization/key/delete.d.ts +1 -0
- package/dist/commands/localization/key/delete.js +24 -0
- package/dist/commands/localization/key/generate-uilm-file.d.ts +1 -0
- package/dist/commands/localization/key/generate-uilm-file.js +29 -0
- package/dist/commands/localization/key/get-by-names.d.ts +1 -0
- package/dist/commands/localization/key/get-by-names.js +24 -0
- package/dist/commands/localization/key/get-language-file-generation-history.d.ts +1 -0
- package/dist/commands/localization/key/get-language-file-generation-history.js +19 -0
- package/dist/commands/localization/key/get-localization-timeline.d.ts +1 -0
- package/dist/commands/localization/key/get-localization-timeline.js +28 -0
- package/dist/commands/localization/key/get-timeline-by-operation-id.d.ts +1 -0
- package/dist/commands/localization/key/get-timeline-by-operation-id.js +21 -0
- package/dist/commands/localization/key/get-timeline.d.ts +1 -0
- package/dist/commands/localization/key/get-timeline.js +25 -0
- package/dist/commands/localization/key/get-uilm-exported-files.d.ts +1 -0
- package/dist/commands/localization/key/get-uilm-exported-files.js +22 -0
- package/dist/commands/localization/key/get-uilm-file.d.ts +1 -0
- package/dist/commands/localization/key/get-uilm-file.js +18 -0
- package/dist/commands/localization/key/get.d.ts +1 -0
- package/dist/commands/localization/key/get.js +17 -0
- package/dist/commands/localization/key/list.d.ts +1 -0
- package/dist/commands/localization/key/list.js +39 -0
- package/dist/commands/localization/key/rollback.d.ts +1 -0
- package/dist/commands/localization/key/rollback.js +24 -0
- package/dist/commands/localization/key/save.d.ts +1 -0
- package/dist/commands/localization/key/save.js +44 -0
- package/dist/commands/localization/key/translate-all.d.ts +1 -0
- package/dist/commands/localization/key/translate-all.js +30 -0
- package/dist/commands/localization/key/translate-and-export.d.ts +7 -0
- package/dist/commands/localization/key/translate-and-export.js +132 -0
- package/dist/commands/localization/key/translate-key.d.ts +1 -0
- package/dist/commands/localization/key/translate-key.js +27 -0
- package/dist/commands/localization/key/translate-keys.d.ts +1 -0
- package/dist/commands/localization/key/translate-keys.js +31 -0
- package/dist/commands/localization/key/uilm-export.d.ts +1 -0
- package/dist/commands/localization/key/uilm-export.js +33 -0
- package/dist/commands/localization/key/uilm-import.d.ts +1 -0
- package/dist/commands/localization/key/uilm-import.js +26 -0
- package/dist/commands/localization/language/delete.d.ts +1 -0
- package/dist/commands/localization/language/delete.js +24 -0
- package/dist/commands/localization/language/list-for-tenant.d.ts +1 -0
- package/dist/commands/localization/language/list-for-tenant.js +14 -0
- package/dist/commands/localization/language/list.d.ts +1 -0
- package/dist/commands/localization/language/list.js +14 -0
- package/dist/commands/localization/language/save.d.ts +1 -0
- package/dist/commands/localization/language/save.js +36 -0
- package/dist/commands/localization/language/set-default.d.ts +1 -0
- package/dist/commands/localization/language/set-default.js +24 -0
- package/dist/commands/localization/module/list-for-tenant.d.ts +1 -0
- package/dist/commands/localization/module/list-for-tenant.js +14 -0
- package/dist/commands/localization/module/list.d.ts +1 -0
- package/dist/commands/localization/module/list.js +14 -0
- package/dist/commands/localization/module/save.d.ts +1 -0
- package/dist/commands/localization/module/save.js +32 -0
- package/dist/commands/localization/module/tag-glossary.d.ts +1 -0
- package/dist/commands/localization/module/tag-glossary.js +28 -0
- package/dist/commands/mail/config/delete.d.ts +1 -0
- package/dist/commands/mail/config/delete.js +24 -0
- package/dist/commands/mail/config/duplicate.d.ts +1 -0
- package/dist/commands/mail/config/duplicate.js +24 -0
- package/dist/commands/mail/config/get.d.ts +1 -0
- package/dist/commands/mail/config/get.js +17 -0
- package/dist/commands/mail/config/list.d.ts +1 -0
- package/dist/commands/mail/config/list.js +14 -0
- package/dist/commands/mail/config/save.d.ts +1 -0
- package/dist/commands/mail/config/save.js +44 -0
- package/dist/commands/mail/mailbox/get.d.ts +1 -0
- package/dist/commands/mail/mailbox/get.js +17 -0
- package/dist/commands/mail/mailbox/list.d.ts +1 -0
- package/dist/commands/mail/mailbox/list.js +24 -0
- package/dist/commands/mail/send.d.ts +1 -0
- package/dist/commands/mail/send.js +40 -0
- package/dist/commands/mail/sendtoany.d.ts +1 -0
- package/dist/commands/mail/sendtoany.js +41 -0
- package/dist/commands/mail/template/clone.d.ts +1 -0
- package/dist/commands/mail/template/clone.js +33 -0
- package/dist/commands/mail/template/delete.d.ts +1 -0
- package/dist/commands/mail/template/delete.js +24 -0
- package/dist/commands/mail/template/get.d.ts +1 -0
- package/dist/commands/mail/template/get.js +17 -0
- package/dist/commands/mail/template/list.d.ts +1 -0
- package/dist/commands/mail/template/list.js +24 -0
- package/dist/commands/mail/template/save.d.ts +1 -0
- package/dist/commands/mail/template/save.js +37 -0
- package/dist/commands/mfa/backup-codes/generate.d.ts +1 -0
- package/dist/commands/mfa/backup-codes/generate.js +22 -0
- package/dist/commands/mfa/backup-codes/list.d.ts +1 -0
- package/dist/commands/mfa/backup-codes/list.js +14 -0
- package/dist/commands/mfa/backup-codes/use.d.ts +1 -0
- package/dist/commands/mfa/backup-codes/use.js +18 -0
- package/dist/commands/mfa/config-get.d.ts +1 -0
- package/dist/commands/mfa/config-get.js +14 -0
- package/dist/commands/mfa/config-save.d.ts +1 -0
- package/dist/commands/mfa/config-save.js +36 -0
- package/dist/commands/mfa/disable.d.ts +1 -0
- package/dist/commands/mfa/disable.js +22 -0
- package/dist/commands/mfa/generate.d.ts +1 -0
- package/dist/commands/mfa/generate.js +22 -0
- package/dist/commands/mfa/method-set.d.ts +1 -0
- package/dist/commands/mfa/method-set.js +20 -0
- package/dist/commands/mfa/resend.d.ts +1 -0
- package/dist/commands/mfa/resend.js +20 -0
- package/dist/commands/mfa/totp-enable.d.ts +10 -0
- package/dist/commands/mfa/totp-enable.js +52 -0
- package/dist/commands/mfa/totp-setup.d.ts +1 -0
- package/dist/commands/mfa/totp-setup.js +15 -0
- package/dist/commands/mfa/totp-verify-setup.d.ts +1 -0
- package/dist/commands/mfa/totp-verify-setup.js +17 -0
- package/dist/commands/mfa/verify.d.ts +1 -0
- package/dist/commands/mfa/verify.js +26 -0
- package/dist/commands/new/web.js +115 -15
- package/dist/commands/notification/delete.d.ts +1 -0
- package/dist/commands/notification/delete.js +24 -0
- package/dist/commands/notification/get.d.ts +1 -0
- package/dist/commands/notification/get.js +17 -0
- package/dist/commands/notification/list.d.ts +1 -0
- package/dist/commands/notification/list.js +22 -0
- package/dist/commands/notification/save.d.ts +1 -0
- package/dist/commands/notification/save.js +34 -0
- package/dist/commands/notifier/list.d.ts +1 -0
- package/dist/commands/notifier/list.js +23 -0
- package/dist/commands/notifier/mark-all-read.d.ts +1 -0
- package/dist/commands/notifier/mark-all-read.js +23 -0
- package/dist/commands/notifier/mark-read.d.ts +1 -0
- package/dist/commands/notifier/mark-read.js +24 -0
- package/dist/commands/notifier/notify.d.ts +1 -0
- package/dist/commands/notifier/notify.js +39 -0
- package/dist/commands/notifier/unread.d.ts +1 -0
- package/dist/commands/notifier/unread.js +25 -0
- package/dist/commands/projects/get.js +16 -14
- package/dist/commands/projects/list.js +2 -7
- package/dist/commands/release/builds/list.js +22 -2
- package/dist/commands/release/deploy.js +122 -29
- package/dist/commands/release/status.js +4 -2
- package/dist/commands/sdk/client.d.ts +1 -0
- package/dist/commands/sdk/client.js +99 -0
- package/dist/commands/secrets/get.d.ts +1 -0
- package/dist/commands/secrets/get.js +21 -0
- package/dist/commands/secrets/save.d.ts +1 -0
- package/dist/commands/secrets/save.js +51 -0
- package/dist/commands/skill/add.d.ts +1 -0
- package/dist/commands/skill/add.js +19 -0
- package/dist/commands/skill/list.d.ts +1 -0
- package/dist/commands/skill/list.js +15 -0
- package/dist/commands/skill/show.d.ts +1 -0
- package/dist/commands/skill/show.js +15 -0
- package/dist/commands/storage/config/delete.d.ts +1 -0
- package/dist/commands/storage/config/delete.js +24 -0
- package/dist/commands/storage/config/get.d.ts +1 -0
- package/dist/commands/storage/config/get.js +17 -0
- package/dist/commands/storage/config/list.d.ts +1 -0
- package/dist/commands/storage/config/list.js +14 -0
- package/dist/commands/storage/config/save.d.ts +1 -0
- package/dist/commands/storage/config/save.js +49 -0
- package/dist/index.js +959 -143
- package/dist/lib/api.d.ts +1 -1
- package/dist/lib/api.js +39 -21
- package/dist/lib/args.d.ts +3 -0
- package/dist/lib/args.js +15 -0
- package/dist/lib/auth.d.ts +5 -2
- package/dist/lib/auth.js +23 -35
- package/dist/lib/config.js +7 -7
- package/dist/lib/json-flag.d.ts +17 -0
- package/dist/lib/json-flag.js +55 -0
- package/dist/lib/project-info.d.ts +33 -0
- package/dist/lib/project-info.js +39 -0
- package/dist/lib/prompt.d.ts +2 -0
- package/dist/lib/prompt.js +28 -0
- package/dist/lib/scaffold-web/dashboard.js +1 -1
- package/dist/lib/scaffold-web/root-files.js +1 -1
- package/dist/lib/secret-store.js +7 -7
- package/dist/lib/skills.d.ts +17 -0
- package/dist/lib/skills.js +69 -0
- package/dist/lib/token.d.ts +2 -0
- package/dist/lib/token.js +12 -0
- package/dist/lib/workspace.d.ts +1 -4
- package/dist/lib/workspace.js +18 -2
- package/dist/skills/blocks-data-gateway-configuration/SKILL.md +204 -0
- package/dist/skills/blocks-data-gateway-crud/SKILL.md +223 -0
- package/dist/skills/blocks-data-storage/SKILL.md +161 -0
- package/dist/skills/blocks-frontend-local-https/SKILL.md +100 -0
- package/dist/skills/blocks-iam-access-control/SKILL.md +49 -0
- package/dist/skills/blocks-iam-access-control/flows/feature-gating.md +38 -0
- package/dist/skills/blocks-iam-access-control/flows/manage-roles-permissions.md +109 -0
- package/dist/skills/blocks-iam-account/SKILL.md +169 -0
- package/dist/skills/blocks-iam-mfa/SKILL.md +124 -0
- package/dist/skills/blocks-iam-organizations/SKILL.md +43 -0
- package/dist/skills/blocks-iam-organizations/flows/admin-mutations.md +89 -0
- package/dist/skills/blocks-iam-organizations/flows/read-and-switch.md +57 -0
- package/dist/skills/blocks-iam-sso-oidc-configuration/SKILL.md +89 -0
- package/dist/skills/blocks-iam-sso-oidc-implementation/SKILL.md +80 -0
- package/dist/skills/blocks-iam-users/SKILL.md +131 -0
- package/dist/skills/blocks-localization-configuration/SKILL.md +149 -0
- package/dist/skills/blocks-localization-implementation/SKILL.md +63 -0
- package/dist/skills/blocks-mail/SKILL.md +95 -0
- package/dist/skills/blocks-notification/SKILL.md +69 -0
- package/dist/skills/blocks-notifier/SKILL.md +107 -0
- package/dist/skills/blocks-onboarding/SKILL.md +78 -0
- package/dist/skills/blocks-release-deployment/SKILL.md +81 -0
- package/dist/skills/blocks-secrets/SKILL.md +81 -0
- package/dist/skills/blocks-storage-configuration/SKILL.md +93 -0
- package/dist/skills/lint.mjs +168 -0
- package/package.json +4 -4
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: blocks-iam-account
|
|
3
|
+
description: "Signed-in (or partially-signed-in) user's own SELISE Blocks IAM account actions via @seliseblocks/client — never raw fetch/curl. Covers activation, forgot/reset/change password, logout(-all), profile bootstrap (iam.me/updateMe), self-service MFA, signup, and login-options discovery. Use for activation/password pages, logout buttons, profile bootstrap, signup forms, or letting a user manage their own MFA. The self-service half of IAM — not admin CRUD on other users (blocks-iam-users/blocks-iam-access-control), not hosted-login redirect (blocks-iam-sso-oidc-implementation)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blocks IAM — Account Self-Service
|
|
7
|
+
|
|
8
|
+
Account-lifecycle and account-security actions the signed-in (or not-yet-fully-signed-in) user takes on **their own** account, all through the single `@seliseblocks/client` instance the scaffold gives you — `blocks new web` wires up `createBlocksClient({ apiUrl, xBlocksKey, oidc, accessToken })` once; every call below hangs off that instance's `.auth`, `.iam`, or `.mfa` namespace. **Never** hand-roll `fetch`/`curl` against `api.seliseblocks.com` for these.
|
|
9
|
+
|
|
10
|
+
Source of truth: `auth-client.ts`, `iam-client.ts`, and `mfa-client.ts` in `@seliseblocks/client`. Every method has a What/Why/How docstring in source — this skill surfaces them, it doesn't add new ones.
|
|
11
|
+
|
|
12
|
+
## Scope: this vs. the other IAM skills
|
|
13
|
+
|
|
14
|
+
- **This skill** — the current user acting on themselves: activate their own invite, reset their own forgotten password, change their own password, log themselves out, read/edit their own profile, sign up, discover login options, enroll/manage their own MFA.
|
|
15
|
+
- **blocks-iam-users / blocks-iam-access-control** — an admin managing *other* users (create, deactivate, grant/revoke access). Different actor, different skill. Don't duplicate that here.
|
|
16
|
+
- **blocks-iam-sso-oidc-implementation** — the hosted-login redirect/callback flow (`auth.idp.initiate`/`redirectToProvider`/`callback`, `oidc.refreshToken`). This skill only covers direct account-lifecycle calls (activate, recover, reset, change-password, logout) that a user takes outside that redirect dance — don't reimplement hosted login here.
|
|
17
|
+
- **blocks-iam-mfa** (not yet written) — the full self-service MFA walkthrough (enrollment UX, challenge flows, backup codes). This skill only notes that `mfa.*` exists and is in scope; go there for depth.
|
|
18
|
+
|
|
19
|
+
## The SDK never owns your session
|
|
20
|
+
|
|
21
|
+
Every method here just relays IAM's request/response. The SDK **does not** read or write cookies, localStorage, or any token store — your app decides where the access token, refresh token, and "am I logged in" flag live, and passes the access token in via the `accessToken` option (string or async callback) on `createBlocksClient`. After `logout`/`logoutAll`, activation, or a password reset, **you** clear/update that app-owned state; the SDK call alone doesn't do it for you.
|
|
22
|
+
|
|
23
|
+
Request/payload types for most of these methods are intentionally loose (`Record<string, unknown>` passthrough — IAM, not the SDK, defines the exact fields). `BlocksLogoutRequest` is the one exception with a typed hint (`refreshToken?: string`). Where the SDK doesn't pin the shape, confirm exact field names against your tenant's IAM contract rather than guessing — the examples below show the well-known fields, not an exhaustive schema.
|
|
24
|
+
|
|
25
|
+
## Activation — finishing account setup
|
|
26
|
+
|
|
27
|
+
Three related calls, all under `blocksClient.auth`, all public (no bearer token needed for `activate`/`validateActivation` — the emailed code is the credential):
|
|
28
|
+
|
|
29
|
+
- **`auth.validateActivation(request)`** — no auth required. Check the activation code/state *before* showing the final "set your password" step, so an expired/invalid link fails fast with a clear message instead of after the user fills out the form.
|
|
30
|
+
- **`auth.activate(request)`** — no auth required. Completes setup for a user created/invited in an inactive state: pass the emailed `code` plus the new password (and whatever else your tenant's activation contract needs, e.g. `firstName`/`lastName`) after your UI confirms password === confirm-password client-side (don't send a confirm field — that's a UI-only check).
|
|
31
|
+
- **`auth.resendActivation(request)`** — Send a new code/link when the old one expired. This call attaches the bearer token if one happens to be configured, but works either way — typical callers are not-yet-active, so don't gate this behind requiring a token.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// after the user opens /activate?code=... and submits password + confirm
|
|
35
|
+
const state = await blocksClient.auth.validateActivation({ code });
|
|
36
|
+
if (!state.valid) {
|
|
37
|
+
// show "this link expired" + a resend option
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
await blocksClient.auth.activate({
|
|
41
|
+
code,
|
|
42
|
+
password,
|
|
43
|
+
firstName,
|
|
44
|
+
lastName
|
|
45
|
+
});
|
|
46
|
+
// account is now active — route to login / hosted-login (blocks-iam-sso-oidc-implementation)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Password — forgot, reset, and authenticated change
|
|
50
|
+
|
|
51
|
+
- **`auth.recover(request)`** — no auth required. Public entry point for "forgot password" — typically just the account's email. Triggers IAM to send a reset link/code.
|
|
52
|
+
- **`auth.resetPassword(request)`** — no auth required. Completes the recovery: pass the emailed reset token plus the new password. IAM owns token validation and password-policy enforcement — surface its response/errors directly rather than pre-validating password rules yourself.
|
|
53
|
+
- **`auth.changePassword(request)`** — requires an access token (an authenticated account-security action, not part of the recovery flow). Use this for a signed-in "change my password" settings-page action — current password + new password.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
// forgot-password page
|
|
57
|
+
await blocksClient.auth.recover({ email });
|
|
58
|
+
|
|
59
|
+
// reset-password page (link from the recovery email)
|
|
60
|
+
await blocksClient.auth.resetPassword({ code, password: newPassword });
|
|
61
|
+
|
|
62
|
+
// signed-in settings page
|
|
63
|
+
await blocksClient.auth.changePassword({ oldPassword, newPassword });
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Logout — end this session or all sessions
|
|
67
|
+
|
|
68
|
+
- **`auth.logout(request = {})`** — Ends the current session; commonly takes `{ refreshToken }` if your app manages a refresh token directly (the typed field on `BlocksLogoutRequest`). If your app relies on the hosted IdP's session cookie instead, an empty `{}` is enough — the SDK always sends the request with `credentials: "include"`.
|
|
69
|
+
- **`auth.logoutAll(request = {})`** — "Sign out everywhere" — invalidates every session for the account, not just the current one. Good for a security settings page next to change-password.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
async function signOut() {
|
|
73
|
+
try {
|
|
74
|
+
await blocksClient.auth.logout({ refreshToken });
|
|
75
|
+
} finally {
|
|
76
|
+
// clear app-owned session state even if the network call fails,
|
|
77
|
+
// so the UI never shows a stale signed-in state
|
|
78
|
+
clearLocalSession();
|
|
79
|
+
navigate("/login");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Profile bootstrap and self-edit
|
|
85
|
+
|
|
86
|
+
- **`iam.me()`** — The current IAM user record: roles, permissions, active organization context, resolved from the access token. This is the right call to bootstrap an app's profile/account page or a permission-gated shell after login — don't reconstruct this from token claims yourself.
|
|
87
|
+
- **`iam.updateMe(request)`** — Updates the CURRENT authenticated user's own profile fields (name, etc., per your tenant's IAM contract). The backend resolves the user id from the token — **never** pass another user's id here; that's `iam.users.update(id, request)` in the admin skill, a different call entirely.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const me = await blocksClient.iam.me();
|
|
91
|
+
// me.data?.roles / me.data?.permissions -> gate nav items, feature flags, etc.
|
|
92
|
+
// (iam.me() wraps the user record in a { data } envelope, not the fields directly)
|
|
93
|
+
|
|
94
|
+
await blocksClient.iam.updateMe({ firstName, lastName });
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Self-service MFA
|
|
98
|
+
|
|
99
|
+
Enrolling, challenging, or turning off MFA for the **signed-in user's own** account, via `blocksClient.mfa.*` (see `mfa-client.ts`'s own docstrings — they call this out as self-service, distinct from `mfa.saveConfig`, which is a tenant/admin policy action, not covered here):
|
|
100
|
+
|
|
101
|
+
- **`mfa.totp.setup()`** — Starts authenticator-app enrollment; render IAM's returned secret/QR in your UI.
|
|
102
|
+
- **`mfa.totp.verifySetup({ code })`** — Confirms enrollment with the 6-digit code from the authenticator app.
|
|
103
|
+
- **`mfa.generate({ mfaType, sendPhoneNumberAsEmailDomain? })`** — Sends an email/SMS OTP challenge; returns an `mfaId` for `resend`/`verify`.
|
|
104
|
+
- **`mfa.resend({ mfaId, sendPhoneNumberAsEmailDomain? })`** — Re-sends a pending OTP.
|
|
105
|
+
- **`mfa.verify({ mfaId, verificationCode, authType, isFromTokenCall? })`** — Confirms an OTP or step-up challenge; set `isFromTokenCall` when verifying as part of a login/token exchange.
|
|
106
|
+
- **`mfa.setMethod({ mfaType })`** — Switches which enrolled method is active.
|
|
107
|
+
- **`mfa.disable()`** — Self-service opt-out, where the tenant's policy allows it.
|
|
108
|
+
- **`mfa.backupCodes.list()`** / **`.generate()`** / **`.use({ code, userId })`** — View remaining recovery codes, mint a fresh set (treat the response as sensitive, show once), or consume one when the primary method is unavailable.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
await blocksClient.mfa.totp.setup();
|
|
112
|
+
await blocksClient.mfa.totp.verifySetup({ code });
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The same self-service surface is also reachable from a terminal via `blocks mfa totp setup/verify-setup/enable`, `blocks mfa generate/resend/verify`, `blocks mfa method set`, `blocks mfa disable`, and `blocks mfa backup-codes list/generate/use` (project-scoped, impersonated-user token). **See also:** `blocks-iam-mfa` for the full enrollment/challenge walkthrough — this section only flags that self-service MFA exists and is in this skill's scope.
|
|
116
|
+
|
|
117
|
+
## Signup and login discovery
|
|
118
|
+
|
|
119
|
+
- **`auth.signup(request)`** — no auth required. Registers a new account; IAM owns account-creation rules — send its expected payload and render its response/errors directly rather than pre-validating fields yourself.
|
|
120
|
+
- **`auth.loginOptions()`** — no auth required. Discovers which login methods the tenant supports; call before rendering the login screen so you only show controls IAM actually accepts.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const options = await blocksClient.auth.loginOptions();
|
|
124
|
+
// options -> render enabled login methods (password, social, etc.)
|
|
125
|
+
|
|
126
|
+
await blocksClient.auth.signup({ email, password, firstName, lastName });
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Signup/invite dedup checks
|
|
130
|
+
|
|
131
|
+
Useful inside a signup or invite form before submit — both still send `x-blocks-key` even though they don't require a signed-in user:
|
|
132
|
+
|
|
133
|
+
- **`iam.users.emailAvailable(query)`** — no auth required. Returns an availability flag (`isAvailable`/`IsAvailable` — IAM's casing varies, check both) for a candidate email.
|
|
134
|
+
- **`iam.users.exists(email)`** — Existence check by email.
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const availability = await blocksClient.iam.users.emailAvailable({ email });
|
|
138
|
+
if (availability.isAvailable === false || availability.IsAvailable === false) {
|
|
139
|
+
// show "email already in use" before the user finishes the form
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Gotchas
|
|
144
|
+
|
|
145
|
+
- **Don't invent payload fields.** Several of these methods (`activate`, `resendActivation`, `validateActivation`, `changePassword`, `recover`, `resetPassword`, `logoutAll`, `updateMe`) take an untyped `Record<string, unknown>` in the SDK — the shape is IAM's contract, not something the client library enforces. Use the well-known fields shown above; confirm anything beyond that against the tenant's actual IAM behavior instead of guessing new field names.
|
|
146
|
+
- **`activate`/`validateActivation`/`recover`/`resetPassword` are public (no bearer token)** — the emailed code/token *is* the credential. `changePassword` and `updateMe` require an access token to be configured on the client (via `accessToken` on `createBlocksClient`). `logout`/`logoutAll`/`resendActivation` will attach a bearer token if one is configured, but don't require it.
|
|
147
|
+
- **`iam.me()` is not `auth.userInfo()` or `auth.isAuthenticated()`.** `auth.userInfo()`/`isAuthenticated()` (OIDC-style claims, session-cookie aware) belong to the SSO/OIDC login-flow territory. `iam.me()` is the full IAM user record — roles, permissions, org context — wrapped in a `{ data }` envelope (`BlocksMeResponse = BlocksQueryResponse<BlocksUser>`), so read `me.data?.roles` etc., not `me.roles` directly.
|
|
148
|
+
- **Always clear local app state after logout, even on failure.** The SDK doesn't clear anything for you; a network error from `logout`/`logoutAll` shouldn't leave the UI showing a signed-in user.
|
|
149
|
+
- **`updateMe` never takes a user id.** If you find yourself passing an id, you want the admin `iam.users.update(id, request)` call instead — wrong skill for that.
|
|
150
|
+
- **Confirm-password fields are UI-only.** IAM's `activate`/`resetPassword`/`changePassword` contracts want the new password once; matching against a second "confirm" field is validated client-side and never sent.
|
|
151
|
+
|
|
152
|
+
## Example trigger prompts
|
|
153
|
+
|
|
154
|
+
- "Activate a new account with the emailed code."
|
|
155
|
+
- "Build the /activate page that sets a password from an invite link."
|
|
156
|
+
- "The activation link expired — let the user request a new one."
|
|
157
|
+
- "Add a forgot-password flow to the login page."
|
|
158
|
+
- "Build the reset-password page for the emailed reset link."
|
|
159
|
+
- "Let a signed-in user change their password from account settings."
|
|
160
|
+
- "Add a logout button."
|
|
161
|
+
- "Add a 'sign out of all devices' option."
|
|
162
|
+
- "Fetch the current user's roles and permissions after login."
|
|
163
|
+
- "Let a user edit their own name on their profile page."
|
|
164
|
+
- "Check if an email is already taken before letting someone submit the signup form."
|
|
165
|
+
- "Register a new account from the signup page."
|
|
166
|
+
- "Show which login methods are enabled before rendering the login screen."
|
|
167
|
+
- "Let a signed-in user enroll in authenticator-app MFA."
|
|
168
|
+
- "Add a 'turn off MFA' option to account security settings."
|
|
169
|
+
- "Let a user view or regenerate their MFA backup codes."
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: blocks-iam-mfa
|
|
3
|
+
description: "Self-service MFA for the signed-in user's own account — TOTP enroll/verify, OTP generate/resend/verify, method switch, disable, backup codes — via `blocksClient.mfa.*` or the project-scoped `blocks mfa *` CLI, plus tenant-wide MFA policy admin (`mfa.saveConfig` / `blocks mfa config get/save`). Use for an MFA settings screen, scripted enrollment/checks, or reading/setting a tenant's MFA policy. Not for admin-forcing MFA onto another specific user."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blocks IAM — MFA (Multi-Factor Authentication)
|
|
7
|
+
|
|
8
|
+
Two different things live under "MFA," and this skill covers both without conflating them:
|
|
9
|
+
|
|
10
|
+
1. **Self-service enrollment/verification** — the signed-in user setting up, challenging, switching, or removing MFA on **their own** account. This is `blocksClient.mfa.*` (minus `saveConfig`) in an app, or `blocks mfa totp *` / `mfa generate` / `mfa resend` / `mfa verify` / `mfa method set` / `mfa disable` / `mfa backup-codes *` from a terminal.
|
|
11
|
+
2. **Tenant-wide MFA policy admin** — whether MFA is enabled/required for the tenant at all, which methods are allowed, backup-code settings, and which roles are required/exempt. This is `blocksClient.mfa.config()` / `mfa.saveConfig(request)`, or `blocks mfa config get` / `mfa config save`. It configures the tenant's rules, not any one user's enrollment state.
|
|
12
|
+
|
|
13
|
+
Source of truth: the `@seliseblocks/client` SDK's `mfa` namespace and the `blocks mfa *` CLI command family — this skill surfaces their documented behavior, it doesn't add new capability.
|
|
14
|
+
|
|
15
|
+
## Scope: this vs. the other IAM skills
|
|
16
|
+
|
|
17
|
+
- **This skill** — the signed-in user's own MFA enrollment/verification, and tenant-wide MFA policy configuration (`config`/`saveConfig`).
|
|
18
|
+
- **blocks-iam-account** — the rest of the signed-in user's own account lifecycle (activation, forgot/reset/change password, logout, profile bootstrap, signup). It links here for MFA depth; don't duplicate that material in this file.
|
|
19
|
+
- **blocks-iam-users** — an admin managing *other* users' IAM records (create, deactivate, grant/revoke access). Nothing in the SDK's `mfa` namespace or the CLI's `mfa` command family lets an admin force-enroll, reset, or disable MFA on a specific *other* user's account — the closest thing is tenant-wide, role-based policy (`mfaRequiredRoles`/`mfaExemptRoles` in `saveConfig`), which applies to a role, not a targeted user id. If a caller wants to act on another named user's MFA specifically, that capability wasn't found in this source; don't invent an endpoint for it.
|
|
20
|
+
|
|
21
|
+
## SDK — `blocksClient.mfa.*`
|
|
22
|
+
|
|
23
|
+
| Method | What |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `mfa.config()` | Reads the tenant's current MFA policy. Tenant-wide, not per-user. |
|
|
26
|
+
| `mfa.saveConfig(request)` | Saves the tenant's MFA policy (enable/require MFA, allowed methods, backup-code settings, required/exempt roles). Admin/tenant-settings action — IAM enforces the required role, the SDK does not gate it. |
|
|
27
|
+
| `mfa.totp.setup()` | Starts authenticator-app enrollment for the signed-in user; render IAM's returned secret/QR payload in your UI. |
|
|
28
|
+
| `mfa.totp.verifySetup({ code })` | Confirms enrollment with the 6-digit code from the authenticator app. |
|
|
29
|
+
| `mfa.generate({ mfaType, sendPhoneNumberAsEmailDomain? })` | Sends an email/SMS OTP challenge; IAM returns an `mfaId` to pass to `resend`/`verify`. |
|
|
30
|
+
| `mfa.resend({ mfaId, sendPhoneNumberAsEmailDomain? })` | Re-sends a pending OTP (e.g. SMS delay, spam filtering). |
|
|
31
|
+
| `mfa.verify({ mfaId, verificationCode, authType, isFromTokenCall? })` | Confirms an OTP or step-up challenge; set `isFromTokenCall` when verifying as part of a login/token exchange rather than a standalone check. |
|
|
32
|
+
| `mfa.setMethod({ mfaType })` | Switches which enrolled method is active for a user with more than one enrolled. |
|
|
33
|
+
| `mfa.disable()` | Self-service opt-out for the signed-in user, where the tenant's policy allows it. |
|
|
34
|
+
| `mfa.backupCodes.list()` | Lists the signed-in user's backup codes (e.g. remaining-count display). |
|
|
35
|
+
| `mfa.backupCodes.generate()` | Mints a fresh set of recovery codes. Treat the response as sensitive and show it to the user only once. |
|
|
36
|
+
| `mfa.backupCodes.use({ code, userId })` | Consumes one backup code to complete login/step-up when the primary method is unavailable. `userId` is the signed-in user's own id, not a target for an admin acting on someone else. |
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// enrollment
|
|
40
|
+
await blocksClient.mfa.totp.setup(); // render the returned secret/QR
|
|
41
|
+
await blocksClient.mfa.totp.verifySetup({ code });
|
|
42
|
+
|
|
43
|
+
// OTP challenge (email/SMS-based methods)
|
|
44
|
+
const { mfaId } = await blocksClient.mfa.generate({ mfaType });
|
|
45
|
+
await blocksClient.mfa.verify({ mfaId, verificationCode, authType });
|
|
46
|
+
|
|
47
|
+
// tenant policy (admin screen only)
|
|
48
|
+
const policy = await blocksClient.mfa.config();
|
|
49
|
+
await blocksClient.mfa.saveConfig({ enableMfa: true, requireMfaForAllUsers: false });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`mfaType` and `authType` are plain numbers defined by IAM's own contract, treated as opaque by both the SDK and CLI — their enum names aren't published anywhere. Neither documents what integer means "TOTP" vs. "SMS" vs. "email" for a given tenant; confirm the value against the tenant's actual IAM config (`mfa.config()` / `blocks mfa config get`) rather than guessing one.
|
|
53
|
+
|
|
54
|
+
## CLI — `blocks mfa *`
|
|
55
|
+
|
|
56
|
+
Every `mfa` command is **project-scoped**: it requires a project already selected (`blocks use <tenantId>`) and calls IAM with an impersonated project token — never the account token. Command segments joined by a space also accept a colon form (`mfa:totp:setup`, `mfa:backup-codes:generate`, etc.) — both resolve to the same command.
|
|
57
|
+
|
|
58
|
+
Tenant policy admin (reads/mutates the tenant's rules, not a user's enrollment):
|
|
59
|
+
|
|
60
|
+
| Command | What |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `blocks mfa config get [--json]` | Reads the tenant's MFA policy. |
|
|
63
|
+
| `blocks mfa config save [--enable] [--require-for-all-users] [--allow-user-opt-out] [--allow-backup-codes] [--backup-codes-count <n>] [--user-mfa-type 0,1] [--required-roles a,b] [--exempt-roles a,b] [--body '<json>'\|--file <path>] [--dry-run] [--yes] [--json]` | Saves the tenant's MFA policy. `--body`/`--file` supplies a base JSON payload; any convenience flag also passed overwrites the matching key on top of it. Requires `--dry-run` (preview only) or `--yes`/an interactive `yes` before it executes. |
|
|
64
|
+
|
|
65
|
+
Self-service enrollment, challenge, and recovery for the calling (impersonated) user:
|
|
66
|
+
|
|
67
|
+
| Command | What |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `blocks mfa totp setup [--json]` | Starts TOTP enrollment; prints IAM's secret/QR payload. |
|
|
70
|
+
| `blocks mfa totp verify-setup <code> [--json]` | Confirms TOTP enrollment with the 6-digit code. |
|
|
71
|
+
| `blocks mfa totp enable --mfa-type <n> [--code <c>] [--dry-run] [--yes] [--json]` | Composed enrollment — see below. |
|
|
72
|
+
| `blocks mfa generate --mfa-type <n> [--send-phone-number-as-email-domain <domain>] [--json]` | Sends an OTP challenge; returns an `mfaId` to pass to `resend`/`verify`. |
|
|
73
|
+
| `blocks mfa resend <mfaId> [--send-phone-number-as-email-domain <domain>] [--json]` | Re-sends a pending OTP. |
|
|
74
|
+
| `blocks mfa verify <mfaId> <code> --auth-type <n> [--from-token-call] [--json]` | Confirms an OTP/step-up challenge. |
|
|
75
|
+
| `blocks mfa method set --mfa-type <n> [--json]` | Switches the impersonated user's active MFA method. |
|
|
76
|
+
| `blocks mfa disable [--dry-run] [--yes] [--json]` | Disables MFA for the impersonated user. Mutating: needs `--dry-run` or `--yes`. |
|
|
77
|
+
| `blocks mfa backup-codes list [--json]` | Lists the impersonated user's backup codes. Read-only. |
|
|
78
|
+
| `blocks mfa backup-codes generate [--dry-run] [--yes] [--json]` | Generates a fresh set, invalidating existing ones. Mutating: needs `--dry-run` or `--yes`. |
|
|
79
|
+
| `blocks mfa backup-codes use <userId> <code> [--json]` | Consumes one backup code. |
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
blocks mfa config get --json # check tenant policy before prompting enrollment
|
|
83
|
+
blocks mfa totp setup # prints secret/QR
|
|
84
|
+
blocks mfa totp verify-setup 123456
|
|
85
|
+
blocks mfa method set --mfa-type 0
|
|
86
|
+
blocks mfa backup-codes generate --dry-run # preview, no call
|
|
87
|
+
blocks mfa backup-codes generate --yes # after explicit confirmation
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## The composed `mfa totp enable` command
|
|
91
|
+
|
|
92
|
+
`mfa totp enable --mfa-type <n>` chains the individual TOTP steps into one enrollment sitting, with one confirmation, rather than four separate commands run at different times:
|
|
93
|
+
|
|
94
|
+
`totp setup` → prints the QR/secret → **verification code** (from `--code`, or an interactive prompt if omitted) → `totp verify-setup <code>` → `method set --mfa-type <n>` → `backup-codes generate --yes`.
|
|
95
|
+
|
|
96
|
+
Two things worth calling out precisely, both confirmed against source:
|
|
97
|
+
|
|
98
|
+
- **`--mfa-type` is required, never defaulted.** The numeric value that means "TOTP" for a given tenant isn't documented anywhere in this CLI or SDK (the same opaque-integer caveat as `mfa generate`/`method set` above) — the command throws rather than guessing one. Look it up (e.g. via `mfa config get`, or ask the user) instead of assuming a value like `0`.
|
|
99
|
+
- **Two separate prompts can block a non-interactive run**, not just one: the command asks the operator to type `yes` before it starts (skipped by `--yes`, same as `--dry-run`), and then, independently, if `--code` isn't passed, it prompts for the verification code from stdin with no timeout — in a non-interactive/agent context with no TTY to answer it, this hangs indefinitely rather than failing fast. An agent or script running this command must pass **both** `--yes` and `--code <c>` (the code sourced from wherever the authenticator output is captured) to avoid a hang.
|
|
100
|
+
- `--dry-run` short-circuits before either prompt and before any network call: it prints the planned step list (`mfa:totp:setup`, the scan/enter-code step, `mfa:totp:verify-setup <code>`, `mfa:method:set <n>`, `mfa:backup-codes:generate`) and exits.
|
|
101
|
+
|
|
102
|
+
Deliberately excluded from this composed command: `mfa config save`. That's the separate tenant-wide policy action covered above, not part of enrolling one user.
|
|
103
|
+
|
|
104
|
+
## Gotchas
|
|
105
|
+
|
|
106
|
+
- **`config`/`saveConfig` (SDK) and `mfa config get`/`config save` (CLI) are tenant policy, not a user's enrollment state.** Don't call these expecting to see or change one user's MFA status — that's every other method/command in this file.
|
|
107
|
+
- **`mfaType`/`authType` are opaque, tenant-defined integers.** Neither the SDK's types nor the CLI documents what number means "TOTP," "SMS," or "email" — confirm against the tenant's own IAM config rather than guessing.
|
|
108
|
+
- **`mfa totp enable` can hang waiting on stdin twice over** if run non-interactively without `--yes` and `--code` — see above. Always pass both when scripting or agent-driving this command.
|
|
109
|
+
- **Backup codes are shown once.** Treat `backupCodes.generate()` / `mfa backup-codes generate`'s response as sensitive; there's no re-display endpoint for the raw codes, only `list()`/`backup-codes list`, which is for a remaining-count style view, not for recovering codes you didn't save.
|
|
110
|
+
- **No admin "force MFA on this specific user" capability was found in this source.** The nearest thing is tenant-wide, role-based policy (`mfaRequiredRoles`/`mfaExemptRoles` via `saveConfig`/`config save`), which targets a role, not a user id. If a request needs a specific other user's MFA changed, that's out of this skill's scope — don't fabricate an endpoint to satisfy it.
|
|
111
|
+
- **Every `mfa` CLI command is project-scoped and impersonation-only**, same rule as the rest of the project-scoped CLI surface — `blocks use <tenantId>` first, or commands fail with `project_not_selected`.
|
|
112
|
+
- **Mutating CLI commands (`config save`, `disable`, `backup-codes generate`, and the composed `totp enable`) require `--dry-run` or `--yes`/an interactive `yes`** before they execute — apply the same confirm-before-mutating discipline an agent uses for any other mutating Blocks CLI command: state the exact change and get explicit go-ahead first.
|
|
113
|
+
|
|
114
|
+
## Example trigger prompts
|
|
115
|
+
|
|
116
|
+
- "Let a signed-in user enroll in authenticator-app (TOTP) MFA."
|
|
117
|
+
- "Build the MFA settings screen: enroll, switch method, disable, view backup codes."
|
|
118
|
+
- "Check whether this tenant requires MFA before showing the enrollment prompt."
|
|
119
|
+
- "Turn on MFA for the whole tenant and require it for the admin role."
|
|
120
|
+
- "Send an OTP code to the user and verify what they typed."
|
|
121
|
+
- "Let a user regenerate their MFA backup codes."
|
|
122
|
+
- "From the terminal, enroll the current project's impersonated user in TOTP MFA end to end."
|
|
123
|
+
- "Run TOTP enrollment non-interactively from a script" → pass both `--yes` and `--code <c>` to `blocks mfa totp enable`, never run it unattended without them.
|
|
124
|
+
- "Read the tenant's current MFA policy from the CLI."
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: blocks-iam-organizations
|
|
3
|
+
description: "Work with organizations (multi-tenant workspaces) via `iam.organizations`/`iam.signupSettings`/`auth.switchOrganization` (SDK, in-app) or `blocks iam organizations *`/`iam signup-settings *` (CLI, project-scoped, `--dry-run`→`--yes`) — never raw fetch/curl. Covers the org switcher, switching active org context (SDK/app-only, no CLI equivalent), public signup policy, and — human-confirmed only — creating/editing organizations and org/signup config. Use for 'org switcher', 'switch organization', 'multi-org', 'create/update an organization', 'organization settings', 'signup settings'. Users/roles within an org are blocks-iam-users/blocks-iam-access-control; SSO/OIDC client setup is blocks-onboarding, portal-optional now."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blocks IAM — Organizations
|
|
7
|
+
|
|
8
|
+
Organizations are the tenancy/workspace unit inside a Blocks project. Two equally real surfaces exist for managing them:
|
|
9
|
+
|
|
10
|
+
- **Inside a Blocks app** — `@seliseblocks/client` SDK calls from app code (`blocksClient` in `src/lib/blocks/client.ts`, from `blocks new web`). Never write raw `fetch`/`curl` against Blocks APIs.
|
|
11
|
+
- **Outside an app UI** — scripting, one-off inspection, CI, an ops task — the `blocks` CLI has a real, project-scoped command surface for the same operations: `blocks iam organizations list/get/create/update/my/config get/config save` and `blocks iam signup-settings get/save`.
|
|
12
|
+
|
|
13
|
+
The one thing neither surface papers over as a gap is `auth.switchOrganization` — there is no `blocks iam organizations switch` or similar; switching the *active session's* org context only makes sense from inside the app that owns that session, so it stays SDK-only.
|
|
14
|
+
|
|
15
|
+
**Prerequisite:** the app is a `blocks new web` scaffold with a project selected. If auth/project state is unknown, run the blocks-onboarding skill first.
|
|
16
|
+
|
|
17
|
+
## The platform boundary — read this before writing any admin-CRUD call
|
|
18
|
+
|
|
19
|
+
Full organization management (create, update, config, signup-settings) **is** exposed today, on both surfaces above. What's restricted isn't the surface but *who authorizes a mutation and when* — organizations are a tenant-isolation boundary, so creating or reconfiguring them carries the same "human explicitly directs this specific change" discipline as the portal-only OIDC provisioning in blocks-onboarding, just enforced on two different mechanisms (SDK call vs. CLI command) instead of one.
|
|
20
|
+
|
|
21
|
+
Concretely: **before wiring up or invoking any `create`/`update`/`saveConfig`/`save` call — SDK or CLI — restate the exact change back to the user in plain terms (which organization, which fields, old value vs. new value) and get an explicit go-ahead.** Never something an agent calls on its own initiative, in an unattended script, or as a side effect of some other task.
|
|
22
|
+
|
|
23
|
+
## Two flows
|
|
24
|
+
|
|
25
|
+
- **[flows/read-and-switch.md](flows/read-and-switch.md)** — the org switcher (`organizations.my`), switching active org context (`auth.switchOrganization`, SDK-only), and public signup policy (`signupSettings.get`). Safe, no special caveat.
|
|
26
|
+
- **[flows/admin-mutations.md](flows/admin-mutations.md)** — creating/editing organizations, org-level config, and signup policy, on both the SDK and CLI surfaces, including the full CLI command reference. Sensitive — human-confirmed only.
|
|
27
|
+
|
|
28
|
+
## Gotchas
|
|
29
|
+
|
|
30
|
+
- **The CLI has real organization/signup-settings commands** — don't tell a user there's no `blocks` command for organizations.
|
|
31
|
+
- **The one genuine gap is `switchOrganization`** — SDK/app-only, no CLI equivalent, don't invent one.
|
|
32
|
+
- **Confirm the payload, not just the intent**, before any mutating call — SDK or CLI. See [flows/admin-mutations.md](flows/admin-mutations.md) for the full discipline.
|
|
33
|
+
- **Multi-org must be enabled** (`isMultiOrgEnabled`) for switching orgs to be meaningful — check this first if a user reports "switching doesn't do anything."
|
|
34
|
+
|
|
35
|
+
## Example trigger prompts
|
|
36
|
+
|
|
37
|
+
- "Add an org switcher to the sidebar using the current user's organizations." → read-and-switch
|
|
38
|
+
- "Let a multi-org user switch which organization they're working in." → read-and-switch
|
|
39
|
+
- "Show the tenant's signup policy on our public signup page." → read-and-switch
|
|
40
|
+
- "Build an admin screen to create a new organization." → admin-mutations (confirm the fields with the user before calling `create`)
|
|
41
|
+
- "Turn on multi-org for this project." → admin-mutations (read `getConfig`/`config get` first, confirm the change, then save)
|
|
42
|
+
- "Is there a `blocks` command to list organizations?" → yes, `blocks iam organizations list` (project-scoped, requires `blocks use <tenantId>` first); use the SDK instead only when the ask is a feature inside the app itself.
|
|
43
|
+
- "Is there a CLI way to switch which organization I'm working in?" → no, that's the one gap — `auth.switchOrganization` is SDK/app-only since it mutates the calling session's own tokens.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Flow: Admin-CRUD surface — confirm the exact change first
|
|
2
|
+
|
|
3
|
+
These mutate tenant-level state. Build them as an explicit feature in an admin settings screen (SDK), or run them as an operator from a terminal with a reviewed `--dry-run` (CLI). Both surfaces exist and are equally real — see "The platform boundary" in [SKILL.md](../SKILL.md).
|
|
4
|
+
|
|
5
|
+
## SDK methods
|
|
6
|
+
|
|
7
|
+
### `organizations.list(query)` / `organizations.get(id)` — browse and inspect
|
|
8
|
+
|
|
9
|
+
Read-only, so no confirmation is needed to call them — but they're part of the admin org-management surface (browsing arbitrary orgs, not just "my own"), so gate the screen itself behind whatever admin permission the app already checks. Typical use: an org-picker/detail view feeding into an edit form, populated before a `create`/`update` call.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
const page = await blocksClient.iam.organizations.list({ Page: 1, PageSize: 20, "Filter.Name": search });
|
|
13
|
+
const org = await blocksClient.iam.organizations.get(organizationId);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### `organizations.create(request)` / `organizations.update(id, request)`
|
|
17
|
+
|
|
18
|
+
Create/edit an organization's record (name, description, contact info, branding, addresses, default roles/permissions for new members, etc. — verify current field names against what the admin UI/API actually accepts rather than assuming they haven't changed).
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// Only after the admin has reviewed and confirmed this exact payload:
|
|
22
|
+
await blocksClient.iam.organizations.create({
|
|
23
|
+
name: "Acme Logistics",
|
|
24
|
+
description: "Acme's logistics division workspace"
|
|
25
|
+
// ...remaining fields the user confirmed
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
await blocksClient.iam.organizations.update(organizationId, {
|
|
29
|
+
name: "Acme Logistics (Renamed)"
|
|
30
|
+
// ...only the fields the user asked to change
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### `organizations.getConfig()` / `organizations.saveConfig(request)` — org-level settings
|
|
35
|
+
|
|
36
|
+
Project/org-wide policy, including multi-org enablement. Read the current config first, show the user the diff of what would change, then save.
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
const current = await blocksClient.iam.organizations.getConfig();
|
|
40
|
+
// ...user reviews current vs. proposed, confirms...
|
|
41
|
+
await blocksClient.iam.organizations.saveConfig({
|
|
42
|
+
...current,
|
|
43
|
+
isMultiOrgEnabled: true
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### `signupSettings.save(request)` — save signup policy
|
|
48
|
+
|
|
49
|
+
Same confirm-first rule: this changes what the public signup screen allows for every future visitor, so restate the exact policy change (e.g., "turn on org creation from signup") before calling.
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
await blocksClient.iam.signupSettings.save({
|
|
53
|
+
...currentSettings,
|
|
54
|
+
allowOrgCreationFromSignup: true
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## CLI surface — scripting/inspection, outside an app UI
|
|
59
|
+
|
|
60
|
+
For anything that isn't a feature inside a running Blocks app (one-off lookups, ops scripts, CI checks), the `blocks` CLI has a matching, project-scoped command for every SDK method above except `switchOrganization` (see [read-and-switch.md](read-and-switch.md)). Every command below requires a project already selected (`blocks use <tenantId>`) — they all call IAM through an impersonated project token via `selectedProject()`, the same tenant scoping the SDK calls get from the app's own session.
|
|
61
|
+
|
|
62
|
+
| CLI command | Maps to | Notes |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| `blocks iam organizations list` | `organizations.list()` | `--search`, `--is-disabled`, `--parent-organization-id`, `--ids <a,b>`, `--page`, `--page-size`, `--sort-by`, `--sort-desc`. Read-only. |
|
|
65
|
+
| `blocks iam organizations get <id>` (or `--id`) | `organizations.get(id)` | Read-only. |
|
|
66
|
+
| `blocks iam organizations my` | `organizations.my()` | Read-only. |
|
|
67
|
+
| `blocks iam organizations create --name <n> [...]` | `organizations.create()` | `--name` (required), `--description`, `--email`, `--phone-number`, `--website-url`, `--default-permissions`, `--default-roles`, or a full `--body '<json>'`/`--file <path.json>`. Mutation. |
|
|
68
|
+
| `blocks iam organizations update <id> [...]` | `organizations.update(id, ...)` | `--name`, `--description`, `--email`, `--phone-number`, `--website-url`, `--currency`, `--industry`, `--locale`, `--time-zone`, `--is-enabled`, or `--body`/`--file`. Mutation. |
|
|
69
|
+
| `blocks iam organizations config get` | `organizations.getConfig()` | Read-only. |
|
|
70
|
+
| `blocks iam organizations config save [...]` | `organizations.saveConfig()` | `--multi-org-enabled`, `--consent-for-multi-org-enable`, `--allow-org-creation-from-signup`, `--allow-org-creation-from-portal`, `--allow-org-creation-from-cloud`, `--allow-org-creation-from-construct`, or `--body`/`--file`. Mutation. |
|
|
71
|
+
| `blocks iam signup-settings get` | `signupSettings.get()` | Read-only. |
|
|
72
|
+
| `blocks iam signup-settings save [...]` | `signupSettings.save()` | `--email-password-signup`, `--sso-signup`, `--default-permissions`, `--default-roles`, or `--body`/`--file`. Mutation. |
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
blocks use <tenantId> # select the project once per session
|
|
76
|
+
blocks iam organizations list --search acme --json
|
|
77
|
+
blocks iam organizations config get --json
|
|
78
|
+
blocks iam organizations config save --multi-org-enabled --dry-run # review the request body first
|
|
79
|
+
blocks iam organizations config save --multi-org-enabled --yes # only after the user confirms
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Every mutating command (`create`, `update`, `config save`, `signup-settings save`) supports `--dry-run` (prints the resolved request body without calling the API) and requires either `--yes` or an interactive `yes` at a confirmation prompt to actually run — the same "state the exact change, get an explicit go-ahead" discipline as the SDK guidance above, just enforced by the CLI itself instead of app code you write.
|
|
83
|
+
|
|
84
|
+
## Gotchas
|
|
85
|
+
|
|
86
|
+
- **The CLI has real organization/signup-settings commands** — don't tell a user there's no `blocks` command for organizations; there is, it's just project-scoped and separate from the SDK path used inside an app.
|
|
87
|
+
- **Confirm the payload, not just the intent**, before any `create`/`update`/`saveConfig`/`signupSettings.save` call — SDK or CLI — restate which organization and which fields are changing, old value vs. new, and wait for a clear yes. On the CLI this means running with `--dry-run` first and only adding `--yes` after that review.
|
|
88
|
+
- **These are legitimate app/operator features, not agent shortcuts.** It's fine to build a "Create Organization" admin screen with a confirm dialog, or run the CLI command yourself with a human's go-ahead — that's the intended use. It's not fine for an agent to call `organizations.create`/`saveConfig` (CLI or SDK) on its own initiative (e.g., to "set things up" for a demo) without that human-in-the-loop step.
|
|
89
|
+
- **Different response shapes per call** — `my()`/`list()` return an array-shaped payload, `get(id)` returns a single organization, `create` returns an id. Don't assume a single envelope shape across all of them; check the actual response before wiring UI to a field path.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Flow: Read / self-service surface (safe, no special caveat)
|
|
2
|
+
|
|
3
|
+
These are read-only or scoped to switching the *caller's own* context. No confirmation ritual needed beyond normal engineering judgment.
|
|
4
|
+
|
|
5
|
+
## `organizations.my()` — the org switcher
|
|
6
|
+
|
|
7
|
+
Returns the signed-in user's own available organizations — the standard source for an org switcher / "pick your workspace" UI. Requires the user to already be authenticated (pair with `useCurrentUser` / `blocksClient.iam.me()` from the onboarding/profile scaffold).
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// src/features/organizations/useMyOrganizations.ts
|
|
11
|
+
import { useQuery } from "@tanstack/react-query";
|
|
12
|
+
import { useAuth } from "../../app/providers/AuthProvider";
|
|
13
|
+
import { blocksClient } from "../../lib/blocks/client";
|
|
14
|
+
|
|
15
|
+
export function useMyOrganizations() {
|
|
16
|
+
const { status } = useAuth();
|
|
17
|
+
return useQuery({
|
|
18
|
+
enabled: status === "authenticated",
|
|
19
|
+
queryFn: () => blocksClient.iam.organizations.my(),
|
|
20
|
+
queryKey: ["iam", "organizations", "my"]
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
CLI equivalent: `blocks iam organizations my` (read-only, project-scoped).
|
|
26
|
+
|
|
27
|
+
## `auth.switchOrganization(request)` — change active org context
|
|
28
|
+
|
|
29
|
+
For a multi-org user, switches which organization the session is scoped to. Pass `{ organizationId, refreshToken }`; the response is a fresh `BlocksAuthResponse` (new tokens for the new org context). **If your app tracks its own session state (stored tokens, an auth context/provider), replace it with this response** — don't just call the endpoint and leave the old tokens in place, or subsequent calls will still act in the old org.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
async function switchToOrganization(organizationId: string) {
|
|
33
|
+
const refreshToken = getRefreshToken(); // however this app's AuthProvider stores it
|
|
34
|
+
const response = await blocksClient.auth.switchOrganization({ organizationId, refreshToken });
|
|
35
|
+
applyAuthResponse(response); // app-owned: persist new tokens, refresh useCurrentUser/useMyOrganizations
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This is user-directed (they picked an org in the switcher) so it doesn't need the admin-CRUD confirmation ritual — but it does change what the rest of the session sees, so trigger it from an explicit user action (selecting an item in the switcher), not silently.
|
|
40
|
+
|
|
41
|
+
**No CLI equivalent exists for this one** — switching the *active session's* org context only makes sense from inside the app that owns that session, so it's SDK/app-only. Don't invent a `blocks iam organizations switch` command.
|
|
42
|
+
|
|
43
|
+
## `signupSettings.get()` — public signup screen
|
|
44
|
+
|
|
45
|
+
Public — no auth required (the SDK still sends `x-blocks-key`). Read this on a public signup page to know the tenant's current signup policy (e.g., whether self-signup or org-creation-from-signup is allowed) before rendering the form.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const settings = await blocksClient.iam.signupSettings.get();
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
CLI equivalent for scripting/inspection: `blocks iam signup-settings get --json` (no SDK needed, no app context needed).
|
|
52
|
+
|
|
53
|
+
## Gotchas
|
|
54
|
+
|
|
55
|
+
- **`switchOrganization` replaces session state.** If the app persists tokens (localStorage, an AuthProvider, React Query cache), apply the new `BlocksAuthResponse` fully — a stale access token after switching orgs will produce confusing "wrong org" data on the next call.
|
|
56
|
+
- **`organizations.my()` needs the user already authenticated** — call it after `iam.me()`/`useCurrentUser` resolves, not before, or you'll get an auth failure that looks like "no orgs" but actually means "not logged in yet."
|
|
57
|
+
- **Multi-org must be enabled** (`isMultiOrgEnabled` via `organizations.getConfig()` — see [admin-mutations.md](admin-mutations.md)) for more than one org per user to be meaningful — if a user reports "switching orgs doesn't do anything," check this first.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: blocks-iam-sso-oidc-configuration
|
|
3
|
+
description: "Enable/configure SSO for a Blocks project — register an OIDC client and identity provider so end users can log into the app via hosted login. Use for 'enable SSO', 'set up an OIDC identity provider', 'configure single sign-on', 'add a login provider'. CLI-driven by default (`blocks auth oidc-clients *` / `auth idp *`, project-scoped, --dry-run→--yes), not portal-only — the portal remains a valid alternative, especially for federated external providers (Google/Azure/Okta). Don't confuse with `blocks login` (the CLI's own login — see blocks-onboarding)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blocks IAM — SSO / OIDC Configuration
|
|
7
|
+
|
|
8
|
+
Setting up SSO for a Blocks project means provisioning two related tenant records: an **OIDC client** (the app-facing public client used for hosted login) and an **identity provider** (the record the hosted-login redirect/callback flow actually authenticates against). Both are exposed by real, implemented `blocks` CLI commands — this is not a portal-only action.
|
|
9
|
+
|
|
10
|
+
## The one thing to get right: which login is this?
|
|
11
|
+
|
|
12
|
+
Don't conflate the CLI's own login with the identity provider this skill configures.
|
|
13
|
+
|
|
14
|
+
| | `blocks login` | The one THIS skill covers |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| What it's for | Lets `blocks` itself authenticate | Lets **end users log into the user's own app** via hosted SSO |
|
|
17
|
+
| Client type | Packaged into the CLI - nothing to register, no secret to hold | Public (browser client, no secret) |
|
|
18
|
+
| Registered via | Nothing to register - just run `blocks login` | `blocks auth oidc-clients save` / `blocks auth idp create`, or the portal |
|
|
19
|
+
| Owned by | **blocks-onboarding** skill | **This skill**, handing off to **blocks-iam-sso-oidc-implementation** |
|
|
20
|
+
|
|
21
|
+
If the user is asking "how do I get `blocks` logged in" or hits `not_logged_in`, that's **blocks-onboarding**, not this skill. This skill is about the identity provider that sits in front of *the user's own application's* login page.
|
|
22
|
+
|
|
23
|
+
## Decision tree
|
|
24
|
+
|
|
25
|
+
All of these commands are project-scoped: they need a selected project (`blocks use <tenantId>` or `--project`) and run against an impersonated project token, not the CLI's own account token.
|
|
26
|
+
|
|
27
|
+
1. **Check for an existing OIDC client.** `blocks auth oidc-clients list [--json]` / `blocks auth oidc-clients get <clientId> [--json]`. `client_secret` is excluded from list/get responses — you only ever see it once, at creation or `rotate-secret` time. If a suitable public client already exists (matching redirect URI / display name), reuse its id — you're done, skip to handoff.
|
|
28
|
+
2. **If none exists, create one:**
|
|
29
|
+
```
|
|
30
|
+
blocks auth oidc-clients save \
|
|
31
|
+
--client-display-name "<app name>" \
|
|
32
|
+
--redirect-uris "https://<app-domain>/login/callback" \
|
|
33
|
+
--require-pkce --active \
|
|
34
|
+
--scope "openid profile" \
|
|
35
|
+
--register-as-identity-provider \
|
|
36
|
+
[--dry-run] [--yes]
|
|
37
|
+
```
|
|
38
|
+
This mirrors exactly what `blocks new web`'s interactive OIDC-client prompt does when scaffolding a new web app. `--register-as-identity-provider` is what turns this from "just an OIDC client" into something the hosted-login redirect flow (`auth.idp.redirectToProvider()` / `auth.idp.callback()`) can authenticate against — per the CLI's own scaffold help text, this registers the client "as a Blocks OIDC identity provider" in the same call. For the common case (your own app logging its own users in via Blocks-hosted login), this single command is usually the entire provisioning step — `blocks new web` never calls `auth idp create` separately.
|
|
39
|
+
3. **Inspect/manage the resulting identity-provider record** with `blocks auth idp list [--json]` / `blocks auth idp get <id> [--json]`. Use `blocks auth idp status <id> --active|--active=false` to enable/disable without deleting, and `blocks auth idp delete <id>` to remove it — deleting an identity provider **also deletes its related OIDC client registration**, so treat `idp delete` as the higher-blast-radius operation of the two.
|
|
40
|
+
4. **`blocks auth idp create`/`update` exist as a separate, more general path** for constructing an identity-provider record directly — most relevant when federating an *external* identity provider (Google, Azure AD, Okta, etc.) rather than using Blocks' own OIDC client as the login mechanism:
|
|
41
|
+
```
|
|
42
|
+
blocks auth idp create --provider <p> --provider-type <t> --protocol <proto> \
|
|
43
|
+
--client-id <id> [--client-secret <secret>] [--display-name] [--issuer] \
|
|
44
|
+
[--scope] [--redirect-uris a,b] [--active] \
|
|
45
|
+
[--body '<json>'|--file <path>] [--dry-run] [--yes]
|
|
46
|
+
```
|
|
47
|
+
`--provider`, `--provider-type`, `--protocol`, and `--client-id` are required on create, and are immutable afterward — `auth idp update <id>` accepts the same flags but IAM requires you to either omit them or echo the existing values exactly. Richer provider configs (JWKS, private keys, initial roles, etc.) go through `--body`/`--file` rather than a dedicated flag. **How exactly a `clientId` passed here pairs with an OIDC client record is not shown anywhere documented** — the two collections are related (per the cascading delete behavior above) but the create/update commands don't expose an explicit "link to this OIDC client" field beyond passing the same id. If you need to federate an external provider, treat `idp create`'s field values as IAM's contract and confirm anything beyond the flags above against the tenant's actual behavior rather than guessing.
|
|
48
|
+
5. **Hand off.** Once a client id (and, if relevant, an identity-provider id) exists, the frontend wiring — login button, callback route, token handling, `client.auth.idp.initiate()`/`redirectToProvider()`/`.callback()` from `@seliseblocks/client` — is owned by **blocks-iam-sso-oidc-implementation**. Do not duplicate that work here; route to it.
|
|
49
|
+
|
|
50
|
+
## Mutation discipline
|
|
51
|
+
|
|
52
|
+
Every create/update/delete/status/rotate-secret command above follows the same pattern as the rest of `blocks`:
|
|
53
|
+
- `--dry-run` prints the request body and target endpoint without sending it (secrets are redacted in the printed body).
|
|
54
|
+
- Without `--dry-run`, the command prompts "Type 'yes' to continue" before mutating anything, unless `--yes` is passed to skip the prompt.
|
|
55
|
+
- These are real tenant-security actions (an identity provider or public OIDC client controls who can authenticate as a given app's users) — always show the user what will happen (favor `--dry-run` first) rather than running mutations silently, and don't add `--yes` to a call the user hasn't actually approved.
|
|
56
|
+
|
|
57
|
+
Never raw `fetch`/`curl` these endpoints to route around the CLI's confirmation/dry-run discipline — use the commands above so the same guardrails apply.
|
|
58
|
+
|
|
59
|
+
## Two verified footguns
|
|
60
|
+
|
|
61
|
+
- **PKCE lives on the OIDC client only — `auth idp create`/`update` has no PKCE field at all.** `requirePkce` is a real flag on `oidc-clients save` (and `blocks new web`'s scaffold sets it to `true`), but `auth idp create`'s body only reads `clientId`, `clientSecret`, `displayName`, `isActive`, `issuer`, `protocol`, `provider`, `providerType`, `redirectUris`, `scope` — there is no `--require-pkce`/`requirePkce` equivalent on the identity-provider record, and no such flag is documented in `blocks auth idp create --help`. Don't go looking for a matching PKCE setting on the identity provider, and don't assume passing one through `--body`/`--file` does anything — the command doesn't read it.
|
|
62
|
+
- **No `wellKnownUrl` (or equivalent discovery-URL) field is exposed by any `auth idp`/`auth oidc-clients` command in source.** `oidc-clients save` has an `--external-discovery-endpoint` flag (`externalDiscoveryEndpoint` in the request body), but its exact purpose/shape and whether it's tenant-relative or absolute is not explained anywhere in the CLI source or its help text, and `auth idp create`/`update` has no discovery/well-known field whatsoever. **Do not assert a well-known URL shape (e.g. one derived from "the project's own tenant id") as fact — this needs live verification against the tenant API**, not a guess. If a well-known/discovery URL matters for what you're building, treat `--external-discovery-endpoint` as the one lead worth testing live, and confirm the exact shape empirically before documenting it as settled.
|
|
63
|
+
|
|
64
|
+
## Secondary, optional: the SDK's `identityProviders` admin methods
|
|
65
|
+
|
|
66
|
+
`@seliseblocks/client` (see `auth-client.ts`, the `readonly identityProviders = { list, get, create, update, updateStatus, delete }` block) also exposes typed methods that call the same identity-provider resource the CLI's `auth idp` commands hit. Reach for this when you're building an **in-app admin settings screen** for a signed-in administrator, where *they* click a button labeled something like "Add identity provider" and *they* fill in a form, in the moment they personally intend to make that change:
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
// A settings page for a signed-in admin user. The admin types into the form
|
|
70
|
+
// and clicks "Save" themselves — the SDK call fires from THEIR click handler.
|
|
71
|
+
async function onSaveClicked(formValues: IdentityProviderFormValues) {
|
|
72
|
+
await client.auth.identityProviders.create(formValues); // admin-initiated, in the moment
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Request/payload types on these SDK methods are intentionally loose (`Record<string, unknown>` passthrough) — confirm field names against the same contract the CLI's `auth idp create` flags document (`provider`, `providerType`, `protocol`, `clientId`, etc.) rather than guessing new ones.
|
|
77
|
+
|
|
78
|
+
## Related skills
|
|
79
|
+
|
|
80
|
+
- **blocks-onboarding** — owns `blocks login` itself (authenticates with no setup, nothing to register or look up). Go there first if `blocks` itself isn't authenticated, or if the user is conflating "logging in the CLI" with "SSO for my app."
|
|
81
|
+
- **blocks-iam-sso-oidc-implementation** — owns everything that happens once an identity provider/client id exists: wiring the login button, callback route, and token/session handling in the scaffolded React app using `@seliseblocks/client`. This skill hands off to it and does not duplicate its content.
|
|
82
|
+
|
|
83
|
+
## Example trigger prompts → routing
|
|
84
|
+
|
|
85
|
+
- "Enable SSO for my project" / "Set up an OIDC identity provider" / "Configure single sign-on for my app" → confirm it's the app's end-user login (not the CLI's), run the decision tree above (`auth oidc-clients list/get` → `auth oidc-clients save --register-as-identity-provider` if none exists), then hand off to **blocks-iam-sso-oidc-implementation**.
|
|
86
|
+
- "Register an OIDC client so users can log in" → `blocks auth oidc-clients list`/`get` first to avoid duplicates, then `blocks auth oidc-clients save` with `--dry-run` shown to the user before confirming.
|
|
87
|
+
- "Can you just create the identity provider via the API so I don't have to click through the portal?" → yes — walk them through `blocks auth oidc-clients save` / `blocks auth idp create` with `--dry-run` first, get explicit confirmation before dropping `--yes`, and mention the portal (https://os.seliseblocks.com) as an alternative if they'd rather use a GUI, especially for federated external providers where they need to register with that provider first.
|
|
88
|
+
- "blocks login isn't working" / "not_logged_in" → this is the CLI's own login, not this skill — route to **blocks-onboarding**.
|
|
89
|
+
- "I want an admin page in my app where I can manage identity providers" → this skill's SDK section applies: help build the settings screen calling `identityProviders.list/create/update/delete` from the admin's own button clicks.
|