@foir/sdk 0.21.0 → 0.23.0
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/CHANGELOG.md +135 -1
- package/README.md +15 -15
- package/dist/app/client.d.ts +93 -86
- package/dist/app/contract/proto/apps/v1/apps_pb.d.ts +14 -13
- package/dist/app/dispatch.d.ts +5 -5
- package/dist/app/errors.d.ts +17 -15
- package/dist/app/index.d.ts +4 -4
- package/dist/app/naming.d.ts +1 -1
- package/dist/app/ticket.d.ts +2 -2
- package/dist/app/vocabulary.generated.d.ts +2 -2
- package/dist/app-contract.js +3 -3
- package/dist/app.js +92 -90
- package/dist/auth/access.d.ts +19 -19
- package/dist/auth/auth.d.ts +251 -117
- package/dist/auth/grant-table.generated.d.ts +5 -4
- package/dist/auth/hosted.d.ts +38 -14
- package/dist/auth/index.d.ts +9 -9
- package/dist/auth/operations.d.ts +153 -33
- package/dist/auth/ops.d.ts +39 -21
- package/dist/auth/session-client.d.ts +3 -3
- package/dist/auth-session.js +3 -3
- package/dist/auth.js +400 -250
- package/dist/client.js +5 -8
- package/dist/codegen/preset.d.ts +1 -1
- package/dist/data/builtins.d.ts +26 -26
- package/dist/data/client.d.ts +3 -3
- package/dist/data/decimal.d.ts +1 -1
- package/dist/data/index.d.ts +1 -1
- package/dist/data/manifest.d.ts +1 -1
- package/dist/data/schema.d.ts +2 -2
- package/dist/data/transport.d.ts +14 -13
- package/dist/data/ws-transport.d.ts +1 -1
- package/dist/data.js +8 -11
- package/dist/graphql/content-client.d.ts +13 -13
- package/dist/index.js +1 -4
- package/dist/live/drift.d.ts +1 -1
- package/dist/media/screen-capture.d.ts +1 -1
- package/dist/next/index.d.ts +2 -2
- package/dist/next/session.d.ts +10 -10
- package/dist/next.js +78 -60
- package/dist/placement/index.d.ts +13 -13
- package/dist/placement.js +127 -116
- package/dist/push.js +62 -44
- package/dist/react/FoirFeedback.d.ts +2 -2
- package/dist/react/FoirProvider.d.ts +24 -24
- package/dist/react/SignIn.d.ts +4 -4
- package/dist/react/UserButton.d.ts +1 -1
- package/dist/react/feedback-notes.d.ts +8 -6
- package/dist/react/index.d.ts +3 -3
- package/dist/react.js +238 -209
- package/dist/realtime/index.d.ts +1 -1
- package/dist/server/callback-client.d.ts +4 -4
- package/dist/server/events-client.d.ts +21 -21
- package/dist/server/operation-types.d.ts +8 -8
- package/dist/server/require-scoped-token.d.ts +3 -3
- package/dist/server/types.d.ts +2 -2
- package/dist/server/verify-scoped-token.d.ts +3 -3
- package/dist/server.js +130 -126
- package/dist/transport/foir-http.d.ts +14 -14
- package/dist/transport/key-kind.d.ts +1 -12
- package/dist/types/index.d.ts +2 -2
- package/package.json +1 -1
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* manifest's hook may subscribe to (an event of the project, that something
|
|
4
4
|
* emits) is the platform's to say: `validateAppManifest` answers it.
|
|
5
5
|
*/
|
|
6
|
-
export declare const APP_HOOK_EVENTS: readonly ["RECORD_CREATED", "RECORD_UPDATED", "RECORD_DELETED", "RECORD_PUBLISHED", "RECORD_UNPUBLISHED", "
|
|
6
|
+
export declare const APP_HOOK_EVENTS: readonly ["RECORD_CREATED", "RECORD_UPDATED", "RECORD_DELETED", "RECORD_PUBLISHED", "RECORD_UNPUBLISHED", "USER_CREATED", "USER_UPDATED", "USER_DELETED", "USER_MERGED", "SESSION_REVOKED", "OPERATION_COMPLETED", "OPERATION_FAILED", "OPERATION_CANCELLED", "OPERATION_TIMED_OUT", "MEMBERSHIP_GRANTED", "MEMBERSHIP_REVOKED", "MEMBERSHIP_ROLE_CHANGED", "TENANT_PLAN_CHANGED", "TENANT_SUBSCRIPTION_STATUS_CHANGED", "PROJECT_CREATED", "PROJECT_ARCHIVED", "INVITATION_ACCEPTED", "IMPORT_COMPLETED", "MIGRATION_APPLIED", "BULK_UPDATE_COMPLETED", "BULK_PUBLISH_COMPLETED", "USER_PREFERENCE_CHANGED", "ORGANIZATION_CREATED", "ORGANIZATION_UPDATED", "ORGANIZATION_MOVED", "ORGANIZATION_SUSPENDED", "ORGANIZATION_RESUMED", "ORGANIZATION_DELETION_SCHEDULED", "ORGANIZATION_DELETION_CANCELLED", "ORGANIZATION_DELETED", "ORGANIZATION_MEMBER_ADDED", "ORGANIZATION_MEMBER_REMOVED", "ORGANIZATION_MEMBER_ROLE_CHANGED", "PROJECT_REACTIVATED"];
|
|
7
7
|
/** An event a hook can name. */
|
|
8
8
|
export type AppHookEvent = (typeof APP_HOOK_EVENTS)[number];
|
|
9
9
|
/**
|
|
10
10
|
* The grants an operation declares as written, in the permission catalogue's
|
|
11
11
|
* names.
|
|
12
12
|
*/
|
|
13
|
-
export declare const APP_GRANTS: readonly ["appconfig:read", "appsecrets:delete", "appsecrets:list", "appsecrets:put", "appsecrets:read", "files:delete", "files:delete.all", "files:read", "files:read.all", "files:write", "files:write.all", "identities:delete", "identities:read", "notifications:consent", "notifications:read", "notifications:write.named", "operations:complete", "organizations:create", "organizations:delete", "status:write", "users:create", "users:read.all", "users:read.named"];
|
|
13
|
+
export declare const APP_GRANTS: readonly ["appconfig:read", "appsecrets:delete", "appsecrets:list", "appsecrets:put", "appsecrets:read", "files:delete", "files:delete.all", "files:read", "files:read.all", "files:write", "files:write.all", "identities:delete", "identities:read", "notifications:consent", "notifications:read", "notifications:write.named", "operations:complete", "organizations:create", "organizations:delete", "project:stand", "status:write", "users:create", "users:read.all", "users:read.named"];
|
|
14
14
|
/** A grant an operation declares as written. */
|
|
15
15
|
export type AppGrant = (typeof APP_GRANTS)[number];
|
|
16
16
|
/**
|
package/dist/app-contract.js
CHANGED
|
@@ -8,9 +8,9 @@ var file_buf_validate_validate = /* @__PURE__ */ fileDesc("ChtidWYvdmFsaWRhdGUvd
|
|
|
8
8
|
|
|
9
9
|
// ../proto-ts/src/apps/v1/apps_pb.js
|
|
10
10
|
import { file_google_protobuf_struct } from "@bufbuild/protobuf/wkt";
|
|
11
|
-
var file_apps_v1_apps = /* @__PURE__ */ fileDesc2("
|
|
11
|
+
var file_apps_v1_apps = /* @__PURE__ */ fileDesc2("ChJhcHBzL3YxL2FwcHMucHJvdG8SB2FwcHMudjEiwQUKCUFwcENvbmZpZxI0CgRuYW1lGAEgASgJQia6SCNyIRhAMh1eW2Etel1bYS16MC05XSooLVthLXowLTldKykqJBIYCgd2ZXJzaW9uGAIgASgJQge6SARyAhABEiMKCG1ldGFkYXRhGAMgASgLMhEuYXBwcy52MS5NZXRhZGF0YRInCgptaWRkbGV3YXJlGAQgASgLMhMuYXBwcy52MS5NaWRkbGV3YXJlEikKC2NyZWRlbnRpYWxzGAUgASgLMhQuYXBwcy52MS5DcmVkZW50aWFscxIwCg9zZXR0aW5nc19zY2hlbWEYBiABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EjAKB3NvdXJjZXMYByADKAsyHy5hcHBzLnYxLkFwcENvbmZpZy5Tb3VyY2VzRW50cnkSLAoFc2lua3MYCCADKAsyHS5hcHBzLnYxLkFwcENvbmZpZy5TaW5rc0VudHJ5EiYKCm9wZXJhdGlvbnMYCSADKAsyEi5hcHBzLnYxLk9wZXJhdGlvbhIcCgVob29rcxgKIAMoCzINLmFwcHMudjEuSG9vaxIXCgJ1aRgLIAEoCzILLmFwcHMudjEuVUkSIQoHaW5ib3VuZBgMIAEoCzIQLmFwcHMudjEuSW5ib3VuZBIiCghmZWF0dXJlcxgNIAMoCzIQLmFwcHMudjEuRmVhdHVyZRIpCgx1c2VyX3NpZ25faW4YDiABKAsyEy5hcHBzLnYxLlVzZXJTaWduSW4aQwoMU291cmNlc0VudHJ5EgsKA2tleRgBIAEoCRIiCgV2YWx1ZRgCIAEoCzITLmFwcHMudjEuU291cmNlVHlwZToCOAEaQwoKU2lua3NFbnRyeRILCgNrZXkYASABKAkSJAoFdmFsdWUYAiABKAsyFS5hcHBzLnYxLlNpbmtDb250cmFjdDoCOAEiIQoKVXNlclNpZ25JbhITCgtkZXNjcmlwdGlvbhgBIAEoCSKjAgoHRmVhdHVyZRIzCgNrZXkYASABKAlCJrpII3IhGEAyHV5bYS16XVthLXowLTldKigtW2EtejAtOV0rKSokEhYKBXRpdGxlGAIgASgJQge6SARyAhABEhMKC2Rlc2NyaXB0aW9uGAMgASgJEg8KB3NldHRpbmcYBCABKAkSDwoHc291cmNlcxgFIAMoCRIUCgx1c2VyX3NpZ25faW4YBiABKAgSQwoVbm90aWZpY2F0aW9uX2NhdGVnb3J5GAcgASgLMiQuYXBwcy52MS5GZWF0dXJlTm90aWZpY2F0aW9uQ2F0ZWdvcnkSOQoQY29uc2VudF9jYXRlZ29yeRgIIAEoCzIfLmFwcHMudjEuRmVhdHVyZUNvbnNlbnRDYXRlZ29yeSKcAQobRmVhdHVyZU5vdGlmaWNhdGlvbkNhdGVnb3J5EhgKB3NldHRpbmcYASABKAlCB7pIBHICEAESJwoDa2V5GAIgASgJQhq6SBdyFRhAMhFeW2Etel1bYS16MC05X10qJBIVCgRuYW1lGAMgASgJQge6SARyAhABEhMKC2Rlc2NyaXB0aW9uGAQgASgJEg4KBm9wdF9pbhgFIAEoCCK0AQoWRmVhdHVyZUNvbnNlbnRDYXRlZ29yeRIYCgdzZXR0aW5nGAEgASgJQge6SARyAhABEicKA2tleRgCIAEoCUIaukgXchUYQDIRXlthLXpdW2EtejAtOV9dKiQSFQoEbmFtZRgDIAEoCUIHukgEcgIQARITCgtkZXNjcmlwdGlvbhgEIAEoCRIrCgdjaGFubmVsGAUgASgJQhq6SBdyFVIFZW1haWxSBHB1c2hSBmluX2FwcCJlCghNZXRhZGF0YRIUCgxkaXNwbGF5X25hbWUYASABKAkSEwoLZGVzY3JpcHRpb24YAiABKAkSDAoEaWNvbhgDIAEoCRIOCgZhdXRob3IYBCABKAkSEAoIaG9tZXBhZ2UYBSABKAkiLQoKTWlkZGxld2FyZRIfCgN1cmwYASABKAlCErpID3INMgteaHR0cHM6Ly8uKyLvAgoLQ3JlZGVudGlhbHMSLwoIc3RyYXRlZ3kYASABKA4yHS5hcHBzLnYxLkNyZWRlbnRpYWxzLlN0cmF0ZWd5EiwKBnNjaGVtYRgCIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIAIgBARIoCgVvYXV0aBgDIAEoCzIULmFwcHMudjEuT0F1dGhDb25maWdIAYgBARIWCg5jb25uZWN0X25vdGljZRgEIAEoCSKpAQoIU3RyYXRlZ3kSGAoUU1RSQVRFR1lfVU5TUEVDSUZJRUQQABISCg5TVFJBVEVHWV9PQVVUSBABEhQKEFNUUkFURUdZX0FQSV9LRVkQAhIaChZTVFJBVEVHWV9TSEFSRURfU0VDUkVUEAMSFAoQU1RSQVRFR1lfU1NIX0tFWRAEEhEKDVNUUkFURUdZX05PTkUQBRIUChBTVFJBVEVHWV9NQU5BR0VEEAZCCQoHX3NjaGVtYUIICgZfb2F1dGgiTAoLT0F1dGhDb25maWcSHAoUYXV0aG9yaXplX3N0YXJ0X3BhdGgYASABKAkSHwoXYXV0aG9yaXplX2NhbGxiYWNrX3BhdGgYAiABKAkiVgoHSW5ib3VuZBIhCgd3ZWJob29rGAEgASgLMhAuYXBwcy52MS5XZWJob29rEigKB2FjY291bnQYAiABKAsyFy5hcHBzLnYxLkFjY291bnRXZWJob29rIhcKB1dlYmhvb2sSDAoEcGF0aBgBIAEoCSI/Cg5BY2NvdW50V2ViaG9vaxIMCgRwYXRoGAEgASgJEg8KB3NldHRpbmcYAiABKAkSDgoGc291cmNlGAMgASgJIt0CCgpTb3VyY2VUeXBlEg0KBWxhYmVsGAEgASgJEi8KBmZpZWxkcxgCIAMoCzIfLmFwcHMudjEuU291cmNlVHlwZS5GaWVsZHNFbnRyeRITCgtuYXR1cmFsX2tleRgDIAEoCRIQCghvcHRpb25hbBgEIAEoCBIWCg5wcm92aXNpb25fb25seRgFIAEoCBIrCglyZWZlcmVuY2UYBiABKAsyGC5hcHBzLnYxLlNvdXJjZVJlZmVyZW5jZRIkCgVvd25lchgHIAEoDjIVLmFwcHMudjEuU3RvcmFnZU93bmVyEhMKC3JlY29tbWVuZGVkGAggASgIEg4KBmxvb2t1cBgJIAMoCRIQCghpZGVudGl0eRgKIAEoCRpGCgtGaWVsZHNFbnRyeRILCgNrZXkYASABKAkSJgoFdmFsdWUYAiABKAsyFy5hcHBzLnYxLlN1Z2dlc3RlZEZpZWxkOgI4ASKqAgoPU291cmNlUmVmZXJlbmNlEhEKCWtleV9maWVsZBgBIAEoCRI0CgZmaWVsZHMYAiADKAsyJC5hcHBzLnYxLlNvdXJjZVJlZmVyZW5jZS5GaWVsZHNFbnRyeRIQCghlbmRwb2ludBgDIAEoCRINCgVob3N0cxgEIAMoCRIqCgdyZXF1ZXN0GAUgASgLMhkuYXBwcy52MS5SZWZlcmVuY2VSZXF1ZXN0EhoKEnJlc3BvbnNlX3RyYW5zZm9ybRgGIAEoCRIdChVjYWNoZV9tYXhfYWdlX3NlY29uZHMYByABKAUaRgoLRmllbGRzRW50cnkSCwoDa2V5GAEgASgJEiYKBXZhbHVlGAIgASgLMhcuYXBwcy52MS5TdWdnZXN0ZWRGaWVsZDoCOAEiswIKEFJlZmVyZW5jZVJlcXVlc3QSDgoGbWV0aG9kGAEgASgJEhUKDXBhdGhfdGVtcGxhdGUYAiABKAkSMwoFcXVlcnkYAyADKAsyJC5hcHBzLnYxLlJlZmVyZW5jZVJlcXVlc3QuUXVlcnlFbnRyeRI3CgdoZWFkZXJzGAQgAygLMiYuYXBwcy52MS5SZWZlcmVuY2VSZXF1ZXN0LkhlYWRlcnNFbnRyeRIVCg1ib2R5X3RlbXBsYXRlGAUgASgJEhUKDWJhdGNoX2NhcGFibGUYBiABKAgaLAoKUXVlcnlFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBGi4KDEhlYWRlcnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIroBCgxTaW5rQ29udHJhY3QSDQoFbGFiZWwYASABKAkSMQoGZmllbGRzGAIgAygLMiEuYXBwcy52MS5TaW5rQ29udHJhY3QuRmllbGRzRW50cnkSEwoLbmF0dXJhbF9rZXkYAyABKAkSEAoIb3B0aW9uYWwYBCABKAgaQQoLRmllbGRzRW50cnkSCwoDa2V5GAEgASgJEiEKBXZhbHVlGAIgASgLMhIuYXBwcy52MS5TaW5rRmllbGQ6AjgBIpYCCg5TdWdnZXN0ZWRGaWVsZBIMCgR0eXBlGAEgASgJEhIKBWxhYmVsGAIgASgJSACIAQESFQoIcmVxdWlyZWQYAyABKAhIAYgBARIsCgZjb25maWcYBCABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0SAKIAQESPQoTc3VwcG9ydGVkX2RpcmVjdGlvbhgFIAEoDjIbLmFwcHMudjEuRmllbGRTeW5jRGlyZWN0aW9uSAOIAQESFgoJcXVlcnlhYmxlGAYgASgISASIAQFCCAoGX2xhYmVsQgsKCV9yZXF1aXJlZEIJCgdfY29uZmlnQhYKFF9zdXBwb3J0ZWRfZGlyZWN0aW9uQgwKCl9xdWVyeWFibGUiWwoJU2lua0ZpZWxkEgwKBHR5cGUYASABKAkSEAoIc2VtYW50aWMYAiABKAkSEAoIcmVxdWlyZWQYAyABKAgSEgoFbGFiZWwYBCABKAlIAIgBAUIICgZfbGFiZWwiqAQKCU9wZXJhdGlvbhI6CgNrZXkYASABKAlCLbpIKnIoGEAyJF4oX18pP1thLXpdW2EtejAtOV9dKigtW2EtejAtOV9dKykqJBIMCgRuYW1lGAIgASgJEhgKC2Rlc2NyaXB0aW9uGAMgASgJSACIAQESHQoIZW5kcG9pbnQYBCABKAlCC7pICHIGMgReLy4qEhQKDGNhcGFiaWxpdGllcxgFIAMoCRIOCgZncmFudHMYDSADKAkSFwoKdGltZW91dF9tcxgGIAEoBUgBiAEBEjIKDHJldHJ5X3BvbGljeRgHIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIAogBARIyCgxpbnB1dF9zY2hlbWEYCCABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0SAOIAQESMwoNb3V0cHV0X3NjaGVtYRgJIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIBIgBARIbCg5zdXBwb3J0c19hc3luYxgKIAEoCEgFiAEBEhkKEXJ1bl9hZnRlcl9pbnN0YWxsGAsgASgIEh4KFnJ1bnNfb25fbWFwcGVkX3NvdXJjZXMYDCABKAhCDgoMX2Rlc2NyaXB0aW9uQg0KC190aW1lb3V0X21zQg8KDV9yZXRyeV9wb2xpY3lCDwoNX2lucHV0X3NjaGVtYUIQCg5fb3V0cHV0X3NjaGVtYUIRCg9fc3VwcG9ydHNfYXN5bmMipgEKBEhvb2sSMwoDa2V5GAEgASgJQia6SCNyIRhAMh1eW2Etel1bYS16MC05XSooLVthLXowLTldKykqJBIMCgRuYW1lGAIgASgJEhYKBWV2ZW50GAMgASgJQge6SARyAhABEicKBmZpbHRlchgEIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSGgoJb3BlcmF0aW9uGAUgASgJQge6SARyAhABIjcKAlVJEjEKCnBsYWNlbWVudHMYASADKAsyHS5hcHBzLnYxLlBsYWNlbWVudERlY2xhcmF0aW9uIsYEChRQbGFjZW1lbnREZWNsYXJhdGlvbhIzCgNrZXkYASABKAlCJrpII3IhGEAyHV5bYS16XVthLXowLTldKigtW2EtejAtOV0rKSokEjQKBnRhcmdldBgCIAEoDjIkLmFwcHMudjEuUGxhY2VtZW50RGVjbGFyYXRpb24uVGFyZ2V0EhIKBW1vZGVsGAMgASgJSACIAQESEgoFZmllbGQYBCABKAlIAYgBARIhChlmaWVsZF9zZWxlY3RlZF9hdF9pbnN0YWxsGAUgASgIEhAKA3RhYhgGIAEoCUgCiAEBEhYKBXRpdGxlGAcgASgJQge6SARyAhABEh8KA3VybBgIIAEoCUISukgPcg0yC15odHRwczovLy4rEh0KEHJlcGxhY2VzX2RlZmF1bHQYCSABKAhIA4gBARIrCgVoaW50cxgKIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIBIgBARIOCgZzY29wZXMYCyADKAkSEAoIc2V0dGluZ3MYDCADKAkSDgoGZ3JhbnRzGA0gAygJInQKBlRhcmdldBIWChJUQVJHRVRfVU5TUEVDSUZJRUQQABIUChBUQVJHRVRfRlVMTF9QQUdFEAESFgoSVEFSR0VUX01BSU5fRURJVE9SEAISEgoOVEFSR0VUX1NJREVCQVIQAxIQCgxUQVJHRVRfRklFTEQQBEIICgZfbW9kZWxCCAoGX2ZpZWxkQgYKBF90YWJCEwoRX3JlcGxhY2VzX2RlZmF1bHRCCAoGX2hpbnRzKqwBChJGaWVsZFN5bmNEaXJlY3Rpb24SJAogRklFTERfU1lOQ19ESVJFQ1RJT05fVU5TUEVDSUZJRUQQABIkCiBGSUVMRF9TWU5DX0RJUkVDVElPTl9TT1VSQ0VfT05MWRABEiIKHkZJRUxEX1NZTkNfRElSRUNUSU9OX1NJTktfT05MWRACEiYKIkZJRUxEX1NZTkNfRElSRUNUSU9OX0JJRElSRUNUSU9OQUwQAyqeAQoMU3RvcmFnZU93bmVyEh0KGVNUT1JBR0VfT1dORVJfVU5TUEVDSUZJRUQQABIZChVTVE9SQUdFX09XTkVSX1BST0pFQ1QQARIeChpTVE9SQUdFX09XTkVSX09SR0FOSVpBVElPThACEhYKElNUT1JBR0VfT1dORVJfVVNFUhAEIgQIAxADKhZTVE9SQUdFX09XTkVSX0NVU1RPTUVSQjVaM2dpdGh1Yi5jb20vZWlkZXN0dWRpby9mb2lyL2dlbi9wcm90by9hcHBzL3YxO2FwcHN2MWIGcHJvdG8z", [file_buf_validate_validate, file_google_protobuf_struct]);
|
|
12
12
|
var AppConfigSchema = /* @__PURE__ */ messageDesc2(file_apps_v1_apps, 0);
|
|
13
|
-
var
|
|
13
|
+
var UserSignInSchema = /* @__PURE__ */ messageDesc2(file_apps_v1_apps, 1);
|
|
14
14
|
var FeatureSchema = /* @__PURE__ */ messageDesc2(file_apps_v1_apps, 2);
|
|
15
15
|
var FeatureNotificationCategorySchema = /* @__PURE__ */ messageDesc2(file_apps_v1_apps, 3);
|
|
16
16
|
var FeatureConsentCategorySchema = /* @__PURE__ */ messageDesc2(file_apps_v1_apps, 4);
|
|
@@ -74,7 +74,6 @@ export {
|
|
|
74
74
|
CredentialsSchema,
|
|
75
75
|
Credentials_Strategy,
|
|
76
76
|
Credentials_StrategySchema,
|
|
77
|
-
CustomerSignInSchema,
|
|
78
77
|
DiscoveredAccountSchema,
|
|
79
78
|
DiscoveredCountSchema,
|
|
80
79
|
DiscoveredFieldGroupSchema,
|
|
@@ -116,6 +115,7 @@ export {
|
|
|
116
115
|
StorageOwnerSchema,
|
|
117
116
|
SuggestedFieldSchema,
|
|
118
117
|
UISchema,
|
|
118
|
+
UserSignInSchema,
|
|
119
119
|
WebhookSchema,
|
|
120
120
|
file_apps_v1_apps,
|
|
121
121
|
file_apps_v1_discovery
|
package/dist/app.js
CHANGED
|
@@ -138,8 +138,8 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
|
|
|
138
138
|
downgrade;
|
|
139
139
|
constructor(downgrade) {
|
|
140
140
|
super(
|
|
141
|
-
`[foir] your
|
|
142
|
-
{ graphQLErrors: [{ message: "
|
|
141
|
+
`[foir] your user token was ${downgrade.userToken} (${downgrade.reason}), so the request was served as ${downgrade.servedAs}`,
|
|
142
|
+
{ graphQLErrors: [{ message: "user token rejected", extensions: { code: "AUTH_DOWNGRADED" } }] }
|
|
143
143
|
);
|
|
144
144
|
this.name = "FoirAuthDowngradedError";
|
|
145
145
|
this.downgrade = downgrade;
|
|
@@ -155,7 +155,7 @@ function reportAuthDowngrade(envelope) {
|
|
|
155
155
|
if (warnedDowngrade === downgrade.reason) return;
|
|
156
156
|
warnedDowngrade = downgrade.reason;
|
|
157
157
|
console.warn(
|
|
158
|
-
`[foir] your
|
|
158
|
+
`[foir] your user token was ${downgrade.userToken} (${downgrade.reason}) \u2014 this request was served as ${downgrade.servedAs}, so auth-targeted content resolved to its anonymous variant. ` + (downgrade.reason === "expired" ? "Re-exchange the token and retry." : "Check which credential you are sending.")
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
161
|
function refusePrunedDocument(json, options) {
|
|
@@ -244,18 +244,18 @@ function appLookupConflictOf(error) {
|
|
|
244
244
|
if (!keyBy.every((field) => typeof field === "string")) return null;
|
|
245
245
|
return { model, lookup, keyBy };
|
|
246
246
|
}
|
|
247
|
-
function
|
|
248
|
-
const unlinked = extensionOf(error, "
|
|
247
|
+
function appUserUnlinkedOf(error) {
|
|
248
|
+
const unlinked = extensionOf(error, "userUnlinked");
|
|
249
249
|
if (!unlinked) return null;
|
|
250
250
|
const { model, identityProvider } = unlinked;
|
|
251
251
|
if (typeof model !== "string" || typeof identityProvider !== "string") return null;
|
|
252
252
|
return { model, identityProvider };
|
|
253
253
|
}
|
|
254
|
-
function
|
|
254
|
+
function userEmailUnavailableReasonOf(value) {
|
|
255
255
|
return typeof value === "string" && value !== "" ? value : null;
|
|
256
256
|
}
|
|
257
|
-
function
|
|
258
|
-
const reason =
|
|
257
|
+
function appUserEmailUnavailableOf(error) {
|
|
258
|
+
const reason = userEmailUnavailableReasonOf(extensionOf(error, "userEmailUnavailable")?.reason);
|
|
259
259
|
return reason ? { reason } : null;
|
|
260
260
|
}
|
|
261
261
|
function isAppFieldWithheld(error, field) {
|
|
@@ -286,13 +286,13 @@ function isSelectableFieldKey(fieldKey) {
|
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
// src/app/client.ts
|
|
289
|
-
var
|
|
290
|
-
function isVerified(
|
|
291
|
-
return typeof
|
|
289
|
+
var USER_FIELDS = "id email status emailVerifiedAt";
|
|
290
|
+
function isVerified(user) {
|
|
291
|
+
return typeof user.emailVerifiedAt === "string" && user.emailVerifiedAt !== "";
|
|
292
292
|
}
|
|
293
|
-
function
|
|
294
|
-
if (!
|
|
295
|
-
return { id:
|
|
293
|
+
function userOf(user) {
|
|
294
|
+
if (!user?.id) return null;
|
|
295
|
+
return { id: user.id, email: user.email ?? "", verified: isVerified(user), status: user.status ?? "" };
|
|
296
296
|
}
|
|
297
297
|
var RECORD_ID_FIELD = "_id";
|
|
298
298
|
var RECORD_NATURAL_KEY_FIELD = "_naturalKey";
|
|
@@ -498,7 +498,7 @@ function createAppClient(config) {
|
|
|
498
498
|
"integrationConfig",
|
|
499
499
|
`query AppInstallConfig {
|
|
500
500
|
integrationConfig {
|
|
501
|
-
name enabled middlewareUrl targetModels webhookUrl config
|
|
501
|
+
name enabled middlewareUrl targetModels webhookUrl config userEmailUnavailable userSignIn
|
|
502
502
|
sources { key model naturalKey mode fields { appField modelField direction } }
|
|
503
503
|
sinks { key model naturalKey fields { appField modelField direction } }
|
|
504
504
|
}
|
|
@@ -515,8 +515,8 @@ function createAppClient(config) {
|
|
|
515
515
|
settings: got.config ?? {},
|
|
516
516
|
sources: bindingsOf(got.sources),
|
|
517
517
|
sinks: bindingsOf(got.sinks),
|
|
518
|
-
|
|
519
|
-
|
|
518
|
+
userEmailUnavailable: userEmailUnavailableReasonOf(got.userEmailUnavailable),
|
|
519
|
+
userSignIn: typeof got.userSignIn === "string" && got.userSignIn !== "" ? got.userSignIn : null
|
|
520
520
|
};
|
|
521
521
|
},
|
|
522
522
|
async credentials() {
|
|
@@ -670,10 +670,10 @@ function createAppClient(config) {
|
|
|
670
670
|
truncated: answer.truncated === true
|
|
671
671
|
};
|
|
672
672
|
},
|
|
673
|
-
|
|
673
|
+
user: {
|
|
674
674
|
async save(input) {
|
|
675
675
|
const { model, identity, data, email, sourceModifiedAt } = input;
|
|
676
|
-
if (identity === "") refuse(`a
|
|
676
|
+
if (identity === "") refuse(`a user's record on ${model} was saved with no identity`);
|
|
677
677
|
const variables = { modelKey: model, identity, data };
|
|
678
678
|
if (email !== void 0 && email !== "") variables.email = email;
|
|
679
679
|
const timed = sourceModifiedAt !== void 0;
|
|
@@ -681,17 +681,17 @@ function createAppClient(config) {
|
|
|
681
681
|
let answer;
|
|
682
682
|
try {
|
|
683
683
|
answer = await field(
|
|
684
|
-
"
|
|
685
|
-
timed ? `mutation
|
|
684
|
+
"saveUserRecord",
|
|
685
|
+
timed ? `mutation AppSaveUserRecord($modelKey: String!, $identity: String!, $email: String, $data: JSON!, $sourceModifiedAt: String) { saveUserRecord(modelKey: $modelKey, identity: $identity, email: $email, data: $data, sourceModifiedAt: $sourceModifiedAt) { record created userCreated stale } }` : `mutation AppSaveUserRecord($modelKey: String!, $identity: String!, $email: String, $data: JSON!) { saveUserRecord(modelKey: $modelKey, identity: $identity, email: $email, data: $data) { record created userCreated } }`,
|
|
686
686
|
variables
|
|
687
687
|
);
|
|
688
688
|
} catch (error) {
|
|
689
|
-
if (
|
|
689
|
+
if (appUserUnlinkedOf(error)) return { unlinked: true };
|
|
690
690
|
throw error;
|
|
691
691
|
}
|
|
692
692
|
const record = answer?.record;
|
|
693
693
|
if (!record || typeof record !== "object" || Array.isArray(record)) {
|
|
694
|
-
return refuse(`
|
|
694
|
+
return refuse(`saveUserRecord reported no error and returned no record on ${model}`);
|
|
695
695
|
}
|
|
696
696
|
return {
|
|
697
697
|
unlinked: false,
|
|
@@ -699,20 +699,20 @@ function createAppClient(config) {
|
|
|
699
699
|
id: recordIdOf(record),
|
|
700
700
|
created: answer?.created === true,
|
|
701
701
|
fieldsWithheld: record.fieldsWithheld === true,
|
|
702
|
-
|
|
702
|
+
userCreated: answer?.userCreated === true,
|
|
703
703
|
stale: answer?.stale === true
|
|
704
704
|
};
|
|
705
705
|
},
|
|
706
706
|
async read(model, identity) {
|
|
707
|
-
if (identity === "") refuse(`a
|
|
707
|
+
if (identity === "") refuse(`a user's record on ${model} was read with no identity`);
|
|
708
708
|
const record = await field(
|
|
709
|
-
"
|
|
710
|
-
`query
|
|
709
|
+
"userRecordByIdentity",
|
|
710
|
+
`query AppUserRecord($modelKey: String!, $identity: String!) { userRecordByIdentity(modelKey: $modelKey, identity: $identity) }`,
|
|
711
711
|
{ modelKey: model, identity }
|
|
712
712
|
);
|
|
713
713
|
if (!record) return null;
|
|
714
714
|
const id = recordIdOf(record);
|
|
715
|
-
if (!id) return refuse(`
|
|
715
|
+
if (!id) return refuse(`userRecordByIdentity answered a record with no id on ${model}`);
|
|
716
716
|
const data = record.data;
|
|
717
717
|
return {
|
|
718
718
|
id,
|
|
@@ -723,79 +723,79 @@ function createAppClient(config) {
|
|
|
723
723
|
};
|
|
724
724
|
},
|
|
725
725
|
async erase(model, identity) {
|
|
726
|
-
if (identity === "") refuse(`a
|
|
726
|
+
if (identity === "") refuse(`a user's record on ${model} was erased with no identity`);
|
|
727
727
|
const answer = await field(
|
|
728
|
-
"
|
|
729
|
-
`mutation
|
|
728
|
+
"eraseUserRecord",
|
|
729
|
+
`mutation AppEraseUserRecord($modelKey: String!, $identity: String!) { eraseUserRecord(modelKey: $modelKey, identity: $identity) { recordDeleted identityRemoved userDeleted userKeptBecause } }`,
|
|
730
730
|
{ modelKey: model, identity }
|
|
731
731
|
);
|
|
732
|
-
if (!answer) return refuse(`
|
|
732
|
+
if (!answer) return refuse(`eraseUserRecord reported no error and returned no answer on ${model}`);
|
|
733
733
|
return {
|
|
734
734
|
recordDeleted: answer.recordDeleted === true,
|
|
735
735
|
identityRemoved: answer.identityRemoved === true,
|
|
736
|
-
|
|
737
|
-
|
|
736
|
+
userDeleted: answer.userDeleted === true,
|
|
737
|
+
userKeptBecause: answer.userKeptBecause ?? null
|
|
738
738
|
};
|
|
739
739
|
}
|
|
740
740
|
}
|
|
741
741
|
},
|
|
742
|
-
|
|
742
|
+
users: {
|
|
743
743
|
async ensure(email) {
|
|
744
744
|
const address = email.trim();
|
|
745
|
-
if (address === "") refuse("a
|
|
746
|
-
const
|
|
747
|
-
"
|
|
748
|
-
`mutation
|
|
745
|
+
if (address === "") refuse("a user was asked for with an empty email");
|
|
746
|
+
const user = await field(
|
|
747
|
+
"createUser",
|
|
748
|
+
`mutation AppEnsureUser($input: CreateAuthUserInput!) { createUser(input: $input) { id email emailVerifiedAt } }`,
|
|
749
749
|
{ input: { email: address, returnExisting: true } }
|
|
750
750
|
);
|
|
751
|
-
if (!
|
|
752
|
-
return { id:
|
|
751
|
+
if (!user?.id) return refuse("createUser reported no error and returned no user");
|
|
752
|
+
return { id: user.id, email: user.email ?? address, verified: isVerified(user) };
|
|
753
753
|
},
|
|
754
754
|
async get(id) {
|
|
755
|
-
if (id.trim() === "") refuse("a
|
|
756
|
-
const
|
|
757
|
-
"
|
|
758
|
-
`query
|
|
755
|
+
if (id.trim() === "") refuse("a user was asked for with an empty id");
|
|
756
|
+
const user = await field(
|
|
757
|
+
"user",
|
|
758
|
+
`query AppUser($id: String) { user(id: $id) { ${USER_FIELDS} } }`,
|
|
759
759
|
{ id }
|
|
760
760
|
);
|
|
761
|
-
return
|
|
761
|
+
return userOf(user);
|
|
762
762
|
},
|
|
763
763
|
async byEmail(email) {
|
|
764
764
|
const address = email.trim();
|
|
765
|
-
if (address === "") refuse("a
|
|
766
|
-
const
|
|
767
|
-
"
|
|
768
|
-
`query
|
|
765
|
+
if (address === "") refuse("a user was asked for with an empty email");
|
|
766
|
+
const user = await field(
|
|
767
|
+
"user",
|
|
768
|
+
`query AppUserByEmail($email: String) { user(email: $email) { ${USER_FIELDS} } }`,
|
|
769
769
|
{ email: address }
|
|
770
770
|
);
|
|
771
|
-
return
|
|
771
|
+
return userOf(user);
|
|
772
772
|
},
|
|
773
773
|
async byIdentity(identity) {
|
|
774
|
-
if (identity === "") refuse("a
|
|
774
|
+
if (identity === "") refuse("a user was asked for with no identity");
|
|
775
775
|
const answer = await field(
|
|
776
|
-
"
|
|
777
|
-
`query
|
|
776
|
+
"userByIdentity",
|
|
777
|
+
`query AppUserByIdentity($identity: String!) { userByIdentity(identity: $identity) }`,
|
|
778
778
|
{ identity }
|
|
779
779
|
);
|
|
780
780
|
return typeof answer === "string" && answer !== "" ? answer : null;
|
|
781
781
|
},
|
|
782
|
-
async identities(
|
|
783
|
-
if (
|
|
782
|
+
async identities(userId) {
|
|
783
|
+
if (userId === "") refuse("a user's identities were asked for with no user");
|
|
784
784
|
const answer = await field(
|
|
785
|
-
"
|
|
786
|
-
`query
|
|
787
|
-
{
|
|
785
|
+
"userIdentitiesById",
|
|
786
|
+
`query AppUserIdentities($userId: ID!) { userIdentitiesById(userId: $userId) }`,
|
|
787
|
+
{ userId }
|
|
788
788
|
);
|
|
789
|
-
if (!Array.isArray(answer)) return refuse("
|
|
789
|
+
if (!Array.isArray(answer)) return refuse("userIdentitiesById reported no error and returned no list");
|
|
790
790
|
return answer.filter((identity) => typeof identity === "string");
|
|
791
791
|
},
|
|
792
792
|
async list(query = {}) {
|
|
793
793
|
const search = query.search?.trim() ?? "";
|
|
794
794
|
const page = await field(
|
|
795
|
-
"
|
|
796
|
-
`query
|
|
797
|
-
|
|
798
|
-
edges { node { ${
|
|
795
|
+
"users",
|
|
796
|
+
`query AppUsers($first: Int, $after: String, $filter: AuthUsersFilterInput) {
|
|
797
|
+
users(first: $first, after: $after, filter: $filter) {
|
|
798
|
+
edges { node { ${USER_FIELDS} } }
|
|
799
799
|
pageInfo { hasNextPage endCursor }
|
|
800
800
|
}
|
|
801
801
|
}`,
|
|
@@ -805,12 +805,12 @@ function createAppClient(config) {
|
|
|
805
805
|
...search !== "" ? { filter: { search } } : {}
|
|
806
806
|
}
|
|
807
807
|
);
|
|
808
|
-
const
|
|
808
|
+
const users = [];
|
|
809
809
|
for (const edge of page?.edges ?? []) {
|
|
810
|
-
const
|
|
811
|
-
if (
|
|
810
|
+
const user = userOf(edge?.node ?? null);
|
|
811
|
+
if (user) users.push(user);
|
|
812
812
|
}
|
|
813
|
-
return {
|
|
813
|
+
return { users, hasMore: page?.pageInfo?.hasNextPage === true, endCursor: page?.pageInfo?.endCursor ?? null };
|
|
814
814
|
}
|
|
815
815
|
},
|
|
816
816
|
organizations: {
|
|
@@ -826,9 +826,10 @@ function createAppClient(config) {
|
|
|
826
826
|
input.settings = { modelKey: settings.modelKey.trim(), data: settings.data };
|
|
827
827
|
}
|
|
828
828
|
if (organization.firstMember !== void 0) {
|
|
829
|
-
if (organization.firstMember.
|
|
830
|
-
input.firstMember = {
|
|
829
|
+
if (organization.firstMember.userId === "") return refuse("a first member names a user");
|
|
830
|
+
input.firstMember = { userId: organization.firstMember.userId };
|
|
831
831
|
}
|
|
832
|
+
if (organization.ownPool === true) input.ownPool = true;
|
|
832
833
|
const answered = settings === void 0 ? "organizationId status" : "organizationId settingsRecordId status";
|
|
833
834
|
const answer = await field(
|
|
834
835
|
"provisionOrganization",
|
|
@@ -856,10 +857,10 @@ function createAppClient(config) {
|
|
|
856
857
|
},
|
|
857
858
|
notifications: {
|
|
858
859
|
async send(notification) {
|
|
859
|
-
if (notification.
|
|
860
|
-
refuse("a notification needs a
|
|
860
|
+
if (notification.userId === "" || notification.title.trim() === "") {
|
|
861
|
+
refuse("a notification needs a user and a title");
|
|
861
862
|
}
|
|
862
|
-
const input = {
|
|
863
|
+
const input = { userId: notification.userId, title: notification.title };
|
|
863
864
|
if (notification.message !== void 0) input.message = notification.message;
|
|
864
865
|
if (notification.category !== void 0) input.category = notification.category;
|
|
865
866
|
if (notification.actionUrl !== void 0) input.actionUrl = notification.actionUrl;
|
|
@@ -880,8 +881,8 @@ function createAppClient(config) {
|
|
|
880
881
|
},
|
|
881
882
|
async setConsent(change) {
|
|
882
883
|
const subject = consentSubject(change);
|
|
883
|
-
if (subject === null) return refuse("a consent change names its
|
|
884
|
-
if (subject.value === "" || change.category === "") return refuse("a consent change needs a
|
|
884
|
+
if (subject === null) return refuse("a consent change names its user by userId or by email, not both");
|
|
885
|
+
if (subject.value === "" || change.category === "") return refuse("a consent change needs a user and a category");
|
|
885
886
|
const input = {
|
|
886
887
|
[subject.by]: subject.value,
|
|
887
888
|
category: change.category,
|
|
@@ -892,11 +893,11 @@ function createAppClient(config) {
|
|
|
892
893
|
if (change.givenElsewhere !== void 0) input.givenElsewhere = change.givenElsewhere;
|
|
893
894
|
if (change.locale !== void 0) input.locale = change.locale;
|
|
894
895
|
const answer = await field(
|
|
895
|
-
"
|
|
896
|
-
`mutation
|
|
896
|
+
"setUserConsent",
|
|
897
|
+
`mutation AppSetUserConsent($input: SetUserConsentInput!) { setUserConsent(input: $input) { stale confirmationPending } }`,
|
|
897
898
|
{ input }
|
|
898
899
|
);
|
|
899
|
-
if (!answer) return refuse("
|
|
900
|
+
if (!answer) return refuse("setUserConsent reported no error and answered nothing");
|
|
900
901
|
return { stale: answer.stale === true, confirmationPending: answer.confirmationPending === true };
|
|
901
902
|
}
|
|
902
903
|
},
|
|
@@ -934,9 +935,9 @@ function createAppClient(config) {
|
|
|
934
935
|
}
|
|
935
936
|
function consentSubject(change) {
|
|
936
937
|
const loose = change;
|
|
937
|
-
if (loose.email !== void 0 && loose.
|
|
938
|
+
if (loose.email !== void 0 && loose.userId !== void 0) return null;
|
|
938
939
|
if (loose.email !== void 0) return { by: "email", value: loose.email.trim() };
|
|
939
|
-
return { by: "
|
|
940
|
+
return { by: "userId", value: loose.userId ?? "" };
|
|
940
941
|
}
|
|
941
942
|
function directionOf(raw) {
|
|
942
943
|
const name = (raw ?? "").replace(/^FIELD_SYNC_DIRECTION_/, "");
|
|
@@ -1150,18 +1151,18 @@ var APP_HOOK_EVENTS = [
|
|
|
1150
1151
|
"RECORD_DELETED",
|
|
1151
1152
|
"RECORD_PUBLISHED",
|
|
1152
1153
|
"RECORD_UNPUBLISHED",
|
|
1153
|
-
"
|
|
1154
|
-
"
|
|
1155
|
-
"
|
|
1156
|
-
"
|
|
1154
|
+
"USER_CREATED",
|
|
1155
|
+
"USER_UPDATED",
|
|
1156
|
+
"USER_DELETED",
|
|
1157
|
+
"USER_MERGED",
|
|
1157
1158
|
"SESSION_REVOKED",
|
|
1158
1159
|
"OPERATION_COMPLETED",
|
|
1159
1160
|
"OPERATION_FAILED",
|
|
1160
1161
|
"OPERATION_CANCELLED",
|
|
1161
1162
|
"OPERATION_TIMED_OUT",
|
|
1162
|
-
"
|
|
1163
|
-
"
|
|
1164
|
-
"
|
|
1163
|
+
"MEMBERSHIP_GRANTED",
|
|
1164
|
+
"MEMBERSHIP_REVOKED",
|
|
1165
|
+
"MEMBERSHIP_ROLE_CHANGED",
|
|
1165
1166
|
"TENANT_PLAN_CHANGED",
|
|
1166
1167
|
"TENANT_SUBSCRIPTION_STATUS_CHANGED",
|
|
1167
1168
|
"PROJECT_CREATED",
|
|
@@ -1171,7 +1172,7 @@ var APP_HOOK_EVENTS = [
|
|
|
1171
1172
|
"MIGRATION_APPLIED",
|
|
1172
1173
|
"BULK_UPDATE_COMPLETED",
|
|
1173
1174
|
"BULK_PUBLISH_COMPLETED",
|
|
1174
|
-
"
|
|
1175
|
+
"USER_PREFERENCE_CHANGED",
|
|
1175
1176
|
"ORGANIZATION_CREATED",
|
|
1176
1177
|
"ORGANIZATION_UPDATED",
|
|
1177
1178
|
"ORGANIZATION_MOVED",
|
|
@@ -1205,6 +1206,7 @@ var APP_GRANTS = [
|
|
|
1205
1206
|
"operations:complete",
|
|
1206
1207
|
"organizations:create",
|
|
1207
1208
|
"organizations:delete",
|
|
1209
|
+
"project:stand",
|
|
1208
1210
|
"status:write",
|
|
1209
1211
|
"users:create",
|
|
1210
1212
|
"users:read.all",
|
|
@@ -1229,12 +1231,12 @@ export {
|
|
|
1229
1231
|
FoirRequestError,
|
|
1230
1232
|
MAX_APP_MANIFEST_BYTES,
|
|
1231
1233
|
RECORD_KEY_RULE,
|
|
1232
|
-
appCustomerEmailUnavailableOf,
|
|
1233
|
-
appCustomerUnlinkedOf,
|
|
1234
1234
|
appLookupConflictOf,
|
|
1235
1235
|
appModelFieldName,
|
|
1236
1236
|
appModelTypeName,
|
|
1237
1237
|
appSelectorEnumValue,
|
|
1238
|
+
appUserEmailUnavailableOf,
|
|
1239
|
+
appUserUnlinkedOf,
|
|
1238
1240
|
createAppClient,
|
|
1239
1241
|
isAppFieldWithheld,
|
|
1240
1242
|
readAppDispatch,
|
package/dist/auth/access.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* What the signed-in
|
|
2
|
+
* What the signed-in user may see: the roles they hold and the scopes those
|
|
3
3
|
* roles resolve to, as the platform resolved them for the request that asked.
|
|
4
4
|
*
|
|
5
5
|
* Use it to decide what to SHOW: a staff menu, an edit button. It guards
|
|
@@ -14,48 +14,48 @@ import { type AuthOpOptions } from './ops';
|
|
|
14
14
|
import { type SessionAdapter } from './auth';
|
|
15
15
|
import type { FoirEnv } from '../graphql/foir-request';
|
|
16
16
|
/**
|
|
17
|
-
* A signed-in
|
|
17
|
+
* A signed-in user's access, as the platform resolved it. Plain data, so it
|
|
18
18
|
* can be returned from a loader or a server component and read on the other
|
|
19
19
|
* side with {@link hasRole} and {@link hasScope}.
|
|
20
20
|
*/
|
|
21
21
|
export interface FoirAccess {
|
|
22
|
-
/** The signed-in
|
|
23
|
-
|
|
22
|
+
/** The signed-in user. */
|
|
23
|
+
userId: string;
|
|
24
24
|
/**
|
|
25
|
-
* The keys of the roles the
|
|
25
|
+
* The keys of the roles the user holds here, now: across the project, and
|
|
26
26
|
* in the organization they stand in. An empty list means they hold none.
|
|
27
27
|
*
|
|
28
28
|
* `null` means the platform did not say, which is not the same thing: treat it
|
|
29
29
|
* as not known, never as "holds no role". {@link hasRole} answers false for
|
|
30
30
|
* it, and {@link requireRole} refuses with `roles_unknown` so an outage is not
|
|
31
|
-
* mistaken for a
|
|
31
|
+
* mistaken for a user who holds no role.
|
|
32
32
|
*/
|
|
33
33
|
roles: string[] | null;
|
|
34
34
|
/**
|
|
35
|
-
* Everything the
|
|
35
|
+
* Everything the user may do through this key: the set the platform's own
|
|
36
36
|
* checks read for the request. Ask it with {@link hasScope} and not by looking
|
|
37
37
|
* for a string, because a wider grant covers a narrower one.
|
|
38
38
|
*/
|
|
39
39
|
scopes: string[];
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
* The access of the
|
|
43
|
-
* carries no
|
|
42
|
+
* The access of the user a token belongs to, or `null` when the request
|
|
43
|
+
* carries no user. Pass the user's access token as
|
|
44
44
|
* `options.bearerToken`.
|
|
45
45
|
*/
|
|
46
|
-
export declare function
|
|
46
|
+
export declare function userAccess(env: FoirEnv, options?: AuthOpOptions): Promise<FoirAccess | null>;
|
|
47
47
|
/**
|
|
48
|
-
* The access of the session's
|
|
48
|
+
* The access of the session's user, or `null` when nobody is signed in.
|
|
49
49
|
* Renews a lapsed session once, as every signed-in read does.
|
|
50
50
|
*/
|
|
51
51
|
export declare function getSessionAccess(adapter: SessionAdapter, env: FoirEnv): Promise<FoirAccess | null>;
|
|
52
52
|
/**
|
|
53
|
-
* Whether the
|
|
53
|
+
* Whether the user holds the role with this key. False when nobody is
|
|
54
54
|
* signed in, and false when their roles are not known.
|
|
55
55
|
*/
|
|
56
56
|
export declare function hasRole(access: FoirAccess | null | undefined, key: string): boolean;
|
|
57
57
|
/**
|
|
58
|
-
* Whether the
|
|
58
|
+
* Whether the user's scopes cover this one, by the platform's rule: a wider
|
|
59
59
|
* reach covers a narrower one (`records:read.all` covers `records:read`), a
|
|
60
60
|
* grant for every model covers one model (`records:write` covers
|
|
61
61
|
* `records:write:post`), and never the other way round. A scope that is not a
|
|
@@ -66,11 +66,11 @@ export declare function hasScope(access: FoirAccess | null | undefined, scope: s
|
|
|
66
66
|
export type FoirAccessDenial =
|
|
67
67
|
/** Nobody is signed in. */
|
|
68
68
|
'signed_out'
|
|
69
|
-
/** The
|
|
69
|
+
/** The user does not hold the role. */
|
|
70
70
|
| 'role_not_held'
|
|
71
|
-
/** The platform did not say which roles the
|
|
71
|
+
/** The platform did not say which roles the user holds. */
|
|
72
72
|
| 'roles_unknown'
|
|
73
|
-
/** The
|
|
73
|
+
/** The user's scopes do not cover the scope. */
|
|
74
74
|
| 'scope_not_held';
|
|
75
75
|
/**
|
|
76
76
|
* What {@link requireRole} and {@link requireScope} throw. Catch it by class or
|
|
@@ -90,16 +90,16 @@ export declare class FoirAccessDeniedError extends Error {
|
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
|
-
* Require a signed-in
|
|
93
|
+
* Require a signed-in user who holds the role with this key, in a server
|
|
94
94
|
* route or a loader. Returns their access; throws
|
|
95
95
|
* {@link FoirAccessDeniedError} otherwise.
|
|
96
96
|
*
|
|
97
|
-
* This keeps a page from rendering for the wrong
|
|
97
|
+
* This keeps a page from rendering for the wrong user. It is not what
|
|
98
98
|
* protects the data: the platform checks every request the page then makes.
|
|
99
99
|
*/
|
|
100
100
|
export declare function requireRole(adapter: SessionAdapter, env: FoirEnv, key: string): Promise<FoirAccess>;
|
|
101
101
|
/**
|
|
102
|
-
* Require a signed-in
|
|
102
|
+
* Require a signed-in user whose scopes cover this one, by the rule
|
|
103
103
|
* {@link hasScope} reads. Returns their access; throws
|
|
104
104
|
* {@link FoirAccessDeniedError} otherwise.
|
|
105
105
|
*/
|