@gasboost/auth 0.4.1 → 0.5.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/README.md CHANGED
@@ -90,6 +90,49 @@ const repository: AppsScriptAuthRepository = {
90
90
 
91
91
  将来的に SheetORM 向け adapter は auth-core とは別 package として提供する想定です。
92
92
 
93
+ ## Authorization
94
+
95
+ アプリケーション内部の認可には、GAS runtime に依存しない `AuthorizationPolicy` と、Backend service の `AppsScriptAuthorization` を利用できます。
96
+
97
+ ```ts
98
+ import {
99
+ AppsScriptAuthorization,
100
+ createAuthorizationTables,
101
+ } from "@gasboost/auth";
102
+ import { AuthorizationPolicy } from "@gasboost/auth/authorization";
103
+
104
+ export const authorizationPolicy = new AuthorizationPolicy({
105
+ project: ["read", "create", "update", "delete"],
106
+ authorization: ["manage"],
107
+ } as const)
108
+ .linkRole("admin", {
109
+ project: ["read", "create", "update", "delete"],
110
+ authorization: ["manage"],
111
+ })
112
+ .linkRole("member", {
113
+ project: ["read"],
114
+ });
115
+
116
+ const authorizationTables = createAuthorizationTables();
117
+
118
+ const authorization = new AppsScriptAuthorization({
119
+ policy: authorizationPolicy,
120
+ repository: authorizationRepository,
121
+ });
122
+ ```
123
+
124
+ `@gasboost/auth/authorization` は pure な subpath export です。Frontend / shared code では `AuthorizationPolicy` だけを import し、Backend で取得した effective permissions の表示制御に同じ `can()` を使えます。
125
+
126
+ ```ts
127
+ const permissions = await authorization.resolve(session.userId);
128
+
129
+ authorizationPolicy.can(permissions, {
130
+ project: ["update"],
131
+ });
132
+ ```
133
+
134
+ Role definition と permission vocabulary は application code が source of truth です。Repository には assignment だけを保存し、未知の role / permission は grant せず fail closed になります。
135
+
93
136
  ## Initialize
94
137
 
95
138
  `AppsScriptAuth` に Repository、GAS runtime、Session 設定、認証方式の設定を渡します。
@@ -0,0 +1,33 @@
1
+ import type { AuthorizationPolicy, EffectivePermissions, PermissionOf, PermissionRequirement, PermissionStatement } from "./AuthorizationPolicy";
2
+ import type { AuthorizationRepository } from "./AuthorizationRepository";
3
+ type PolicyStatement<TPolicy> = TPolicy extends AuthorizationPolicy<infer TStatement, string> ? TStatement : never;
4
+ type PolicyRole<TPolicy> = TPolicy extends {
5
+ readonly $types: {
6
+ readonly role: infer TRole;
7
+ };
8
+ } ? Extract<TRole, string> : never;
9
+ type PolicyPermission<TPolicy> = TPolicy extends {
10
+ readonly $types: {
11
+ readonly permission: infer TPermission;
12
+ };
13
+ } ? Extract<TPermission, string> : never;
14
+ export declare class AppsScriptAuthorization<TPolicy extends AuthorizationPolicy<PermissionStatement, string>> {
15
+ readonly role: {
16
+ assign(userId: string, role: PolicyRole<TPolicy>): Promise<void>;
17
+ revoke(userId: string, role: PolicyRole<TPolicy>): Promise<void>;
18
+ };
19
+ readonly permission: {
20
+ allow(userId: string, permission: PolicyPermission<TPolicy>): Promise<void>;
21
+ deny(userId: string, permission: PolicyPermission<TPolicy>): Promise<void>;
22
+ revoke(userId: string, permission: PolicyPermission<TPolicy>): Promise<void>;
23
+ };
24
+ private readonly policy;
25
+ private readonly repository;
26
+ constructor({ policy, repository, }: {
27
+ policy: TPolicy;
28
+ repository: AuthorizationRepository;
29
+ });
30
+ resolve(userId: string): Promise<EffectivePermissions<PermissionOf<PolicyStatement<TPolicy>>>>;
31
+ can(userId: string, requirement: PermissionRequirement<PolicyStatement<TPolicy>>): Promise<boolean>;
32
+ }
33
+ export {};
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppsScriptAuthorization = void 0;
4
+ class AppsScriptAuthorization {
5
+ role;
6
+ permission;
7
+ policy;
8
+ repository;
9
+ constructor({ policy, repository, }) {
10
+ this.policy = policy;
11
+ this.repository = repository;
12
+ this.role = {
13
+ assign: (userId, role) => this.repository.role.assign(userId, role),
14
+ revoke: (userId, role) => this.repository.role.revoke(userId, role),
15
+ };
16
+ this.permission = {
17
+ allow: (userId, permission) => this.repository.permission.set(userId, permission, "allow"),
18
+ deny: (userId, permission) => this.repository.permission.set(userId, permission, "deny"),
19
+ revoke: (userId, permission) => this.repository.permission.revoke(userId, permission),
20
+ };
21
+ }
22
+ async resolve(userId) {
23
+ const [roles, permissions] = await Promise.all([
24
+ this.repository.role.findByUserId(userId),
25
+ this.repository.permission.findByUserId(userId),
26
+ ]);
27
+ return this.policy.resolve({
28
+ roles,
29
+ permissions,
30
+ });
31
+ }
32
+ async can(userId, requirement) {
33
+ return this.policy.can(await this.resolve(userId), requirement);
34
+ }
35
+ }
36
+ exports.AppsScriptAuthorization = AppsScriptAuthorization;
@@ -0,0 +1,32 @@
1
+ export type PermissionStatement = Record<string, readonly string[]>;
2
+ export type PermissionOf<TStatement extends PermissionStatement> = {
3
+ [TResource in Extract<keyof TStatement, string>]: `${TResource}:${Extract<TStatement[TResource][number], string>}`;
4
+ }[Extract<keyof TStatement, string>];
5
+ export type PermissionRequirement<TStatement extends PermissionStatement> = {
6
+ readonly [TResource in keyof TStatement]?: readonly TStatement[TResource][number][];
7
+ };
8
+ export type EffectivePermissions<TPermission extends string> = readonly TPermission[];
9
+ export type PermissionEffect = "allow" | "deny";
10
+ export type StoredPermissionOverride = {
11
+ readonly permission: string;
12
+ readonly effect: PermissionEffect;
13
+ };
14
+ export type AuthorizationResolutionInput = {
15
+ readonly roles: readonly string[];
16
+ readonly permissions: readonly StoredPermissionOverride[];
17
+ };
18
+ type RoleGrantMap = ReadonlyMap<string, readonly string[]>;
19
+ export declare class AuthorizationPolicy<const TStatement extends PermissionStatement, TRole extends string = never> {
20
+ readonly statement: TStatement;
21
+ readonly $types: {
22
+ readonly role: TRole;
23
+ readonly permission: PermissionOf<TStatement>;
24
+ };
25
+ private readonly permissions;
26
+ private readonly roleGrants;
27
+ constructor(statement: TStatement, roleGrants?: RoleGrantMap);
28
+ linkRole<const TName extends string, const TRequirement extends PermissionRequirement<TStatement>>(name: TName, requirement: TRequirement): AuthorizationPolicy<TStatement, TRole | TName>;
29
+ resolve(input: AuthorizationResolutionInput): EffectivePermissions<PermissionOf<TStatement>>;
30
+ can(permissions: EffectivePermissions<PermissionOf<TStatement>>, requirement: PermissionRequirement<TStatement>): boolean;
31
+ }
32
+ export {};
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthorizationPolicy = void 0;
4
+ function flattenRequirement(requirement) {
5
+ const permissions = [];
6
+ for (const [resource, actions] of Object.entries(requirement)) {
7
+ for (const action of actions ?? []) {
8
+ permissions.push(`${resource}:${action}`);
9
+ }
10
+ }
11
+ return permissions;
12
+ }
13
+ function unique(values) {
14
+ return [...new Set(values)];
15
+ }
16
+ class AuthorizationPolicy {
17
+ statement;
18
+ $types;
19
+ permissions;
20
+ roleGrants;
21
+ constructor(statement, roleGrants = new Map()) {
22
+ this.statement = statement;
23
+ this.permissions = new Set(flattenRequirement(statement));
24
+ this.roleGrants = roleGrants;
25
+ }
26
+ linkRole(name, requirement) {
27
+ return new AuthorizationPolicy(this.statement, new Map([
28
+ ...this.roleGrants,
29
+ [name, unique(flattenRequirement(requirement))],
30
+ ]));
31
+ }
32
+ resolve(input) {
33
+ const deniedPermissions = new Set(input.permissions
34
+ .filter(({ effect }) => effect === "deny")
35
+ .map(({ permission }) => permission)
36
+ .filter((permission) => this.permissions.has(permission)));
37
+ const resolved = new Set();
38
+ for (const { effect, permission } of input.permissions) {
39
+ if (effect === "allow" &&
40
+ this.permissions.has(permission) &&
41
+ !deniedPermissions.has(permission)) {
42
+ resolved.add(permission);
43
+ }
44
+ }
45
+ for (const role of input.roles) {
46
+ const permissions = this.roleGrants.get(role);
47
+ if (permissions === undefined) {
48
+ continue;
49
+ }
50
+ for (const permission of permissions) {
51
+ if (!deniedPermissions.has(permission)) {
52
+ resolved.add(permission);
53
+ }
54
+ }
55
+ }
56
+ return [...resolved];
57
+ }
58
+ can(permissions, requirement) {
59
+ const granted = new Set(permissions);
60
+ return flattenRequirement(requirement).every((permission) => granted.has(permission));
61
+ }
62
+ }
63
+ exports.AuthorizationPolicy = AuthorizationPolicy;
@@ -0,0 +1,13 @@
1
+ import type { StoredPermissionOverride } from "./AuthorizationPolicy";
2
+ export interface AuthorizationRepository {
3
+ readonly role: {
4
+ findByUserId(userId: string): Promise<readonly string[]>;
5
+ assign(userId: string, role: string): Promise<void>;
6
+ revoke(userId: string, role: string): Promise<void>;
7
+ };
8
+ readonly permission: {
9
+ findByUserId(userId: string): Promise<readonly StoredPermissionOverride[]>;
10
+ set(userId: string, permission: string, effect: StoredPermissionOverride["effect"]): Promise<void>;
11
+ revoke(userId: string, permission: string): Promise<void>;
12
+ };
13
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export { AuthorizationPolicy, type AuthorizationResolutionInput, type EffectivePermissions, type PermissionEffect, type PermissionOf, type PermissionRequirement, type PermissionStatement, type StoredPermissionOverride, } from "./AuthorizationPolicy";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthorizationPolicy = void 0;
4
+ var AuthorizationPolicy_1 = require("./AuthorizationPolicy");
5
+ Object.defineProperty(exports, "AuthorizationPolicy", { enumerable: true, get: function () { return AuthorizationPolicy_1.AuthorizationPolicy; } });
package/dist/index.d.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  export { AppsScriptAuth } from "./AppsScriptAuth";
2
+ export { AppsScriptAuthorization } from "./authorization/AppsScriptAuthorization";
2
3
  export type { AppsScriptAuthRepository } from "./storage/AppsScriptAuthRepository";
4
+ export type { AuthorizationRepository } from "./authorization/AuthorizationRepository";
5
+ export type { EffectivePermissions, PermissionEffect, PermissionOf, PermissionRequirement, PermissionStatement, StoredPermissionOverride, } from "./authorization/AuthorizationPolicy";
3
6
  export type { AuthSchema, AuthSchemaOptions } from "./schema/AuthSchema";
4
7
  export { createAuthTables } from "./schema/createAuthTables";
8
+ export type { AuthorizationSchema, AuthorizationSchemaOptions, } from "./schema/AuthorizationSchema";
9
+ export { createAuthorizationTables } from "./schema/createAuthorizationTables";
5
10
  export { authPattern, type AuthPattern } from "./AuthPattern";
6
11
  export { Account } from "./domain/Account";
7
12
  export { User } from "./domain/User";
package/dist/index.js CHANGED
@@ -1,10 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EmailPasswordIdentity = exports.AppsScriptIdentity = exports.PasswordReset = exports.PasswordCredential = exports.Password = exports.HashedPassword = exports.User = exports.Account = exports.authPattern = exports.createAuthTables = exports.AppsScriptAuth = void 0;
3
+ exports.EmailPasswordIdentity = exports.AppsScriptIdentity = exports.PasswordReset = exports.PasswordCredential = exports.Password = exports.HashedPassword = exports.User = exports.Account = exports.authPattern = exports.createAuthorizationTables = exports.createAuthTables = exports.AppsScriptAuthorization = exports.AppsScriptAuth = void 0;
4
4
  var AppsScriptAuth_1 = require("./AppsScriptAuth");
5
5
  Object.defineProperty(exports, "AppsScriptAuth", { enumerable: true, get: function () { return AppsScriptAuth_1.AppsScriptAuth; } });
6
+ var AppsScriptAuthorization_1 = require("./authorization/AppsScriptAuthorization");
7
+ Object.defineProperty(exports, "AppsScriptAuthorization", { enumerable: true, get: function () { return AppsScriptAuthorization_1.AppsScriptAuthorization; } });
6
8
  var createAuthTables_1 = require("./schema/createAuthTables");
7
9
  Object.defineProperty(exports, "createAuthTables", { enumerable: true, get: function () { return createAuthTables_1.createAuthTables; } });
10
+ var createAuthorizationTables_1 = require("./schema/createAuthorizationTables");
11
+ Object.defineProperty(exports, "createAuthorizationTables", { enumerable: true, get: function () { return createAuthorizationTables_1.createAuthorizationTables; } });
8
12
  var AuthPattern_1 = require("./AuthPattern");
9
13
  Object.defineProperty(exports, "authPattern", { enumerable: true, get: function () { return AuthPattern_1.authPattern; } });
10
14
  var Account_1 = require("./domain/Account");
@@ -0,0 +1,64 @@
1
+ export type AuthorizationSchemaOptions = {
2
+ role?: {
3
+ modelName?: string;
4
+ fields?: {
5
+ id?: string;
6
+ userId?: string;
7
+ role?: string;
8
+ };
9
+ };
10
+ permission?: {
11
+ modelName?: string;
12
+ fields?: {
13
+ id?: string;
14
+ userId?: string;
15
+ permission?: string;
16
+ effect?: string;
17
+ };
18
+ };
19
+ };
20
+ export type AuthorizationSchema = {
21
+ role: {
22
+ modelName: string;
23
+ fields: {
24
+ id: string;
25
+ userId: string;
26
+ role: string;
27
+ };
28
+ };
29
+ permission: {
30
+ modelName: string;
31
+ fields: {
32
+ id: string;
33
+ userId: string;
34
+ permission: string;
35
+ effect: string;
36
+ };
37
+ };
38
+ };
39
+ type Section<O, K extends PropertyKey> = K extends keyof O ? O[K] : undefined;
40
+ type Fields<T> = [T] extends [null | undefined] ? undefined : "fields" extends keyof NonNullable<T> ? NonNullable<T>["fields"] : undefined;
41
+ type PropertyOrDefault<T, K extends PropertyKey, Default extends string> = [
42
+ T
43
+ ] extends [null | undefined] ? Default : K extends keyof NonNullable<T> ? Exclude<NonNullable<T>[K], undefined> extends infer Value ? [Value] extends [never] ? Default : Value extends string ? Value : Default : Default : Default;
44
+ export type ResolveAuthorizationSchema<O extends AuthorizationSchemaOptions> = {
45
+ role: {
46
+ modelName: PropertyOrDefault<Section<O, "role">, "modelName", "authorizationRole">;
47
+ fields: {
48
+ id: PropertyOrDefault<Fields<Section<O, "role">>, "id", "id">;
49
+ userId: PropertyOrDefault<Fields<Section<O, "role">>, "userId", "userId">;
50
+ role: PropertyOrDefault<Fields<Section<O, "role">>, "role", "role">;
51
+ };
52
+ };
53
+ permission: {
54
+ modelName: PropertyOrDefault<Section<O, "permission">, "modelName", "authorizationPermission">;
55
+ fields: {
56
+ id: PropertyOrDefault<Fields<Section<O, "permission">>, "id", "id">;
57
+ userId: PropertyOrDefault<Fields<Section<O, "permission">>, "userId", "userId">;
58
+ permission: PropertyOrDefault<Fields<Section<O, "permission">>, "permission", "permission">;
59
+ effect: PropertyOrDefault<Fields<Section<O, "permission">>, "effect", "effect">;
60
+ };
61
+ };
62
+ };
63
+ export declare function resolveAuthorizationSchema<const O extends AuthorizationSchemaOptions>(options: O): ResolveAuthorizationSchema<O>;
64
+ export {};
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveAuthorizationSchema = resolveAuthorizationSchema;
4
+ function resolveAuthorizationSchema(options) {
5
+ return {
6
+ role: {
7
+ modelName: options.role?.modelName ?? "authorizationRole",
8
+ fields: {
9
+ id: options.role?.fields?.id ?? "id",
10
+ userId: options.role?.fields?.userId ?? "userId",
11
+ role: options.role?.fields?.role ?? "role",
12
+ },
13
+ },
14
+ permission: {
15
+ modelName: options.permission?.modelName ?? "authorizationPermission",
16
+ fields: {
17
+ id: options.permission?.fields?.id ?? "id",
18
+ userId: options.permission?.fields?.userId ?? "userId",
19
+ permission: options.permission?.fields?.permission ?? "permission",
20
+ effect: options.permission?.fields?.effect ?? "effect",
21
+ },
22
+ },
23
+ };
24
+ }
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ import { type AuthorizationSchema, type AuthorizationSchemaOptions } from "./AuthorizationSchema";
3
+ type RoleShape<S extends AuthorizationSchema> = {
4
+ [K in S["role"]["fields"]["id"] | S["role"]["fields"]["userId"] | S["role"]["fields"]["role"]]: z.ZodString;
5
+ };
6
+ type PermissionShape<S extends AuthorizationSchema> = {
7
+ [K in S["permission"]["fields"]["id"] | S["permission"]["fields"]["userId"] | S["permission"]["fields"]["permission"] | S["permission"]["fields"]["effect"]]: K extends S["permission"]["fields"]["effect"] ? z.ZodEnum<{
8
+ allow: "allow";
9
+ deny: "deny";
10
+ }> : z.ZodString;
11
+ };
12
+ export declare function createAuthorizationTables<const O extends AuthorizationSchemaOptions = Record<never, never>>(options?: O): {
13
+ readonly schema: import("./AuthorizationSchema").ResolveAuthorizationSchema<O>;
14
+ readonly role: import("@gasboost/table").TableDefinition<["role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never] extends [null | undefined] ? "authorizationRole" : "modelName" extends infer T_1 ? T_1 extends "modelName" ? T_1 extends keyof NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never> ? Exclude<NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never>[T_1], undefined> extends infer Value ? [Value] extends [never] ? "authorizationRole" : Value extends string ? Value : "authorizationRole" : "authorizationRole" : "authorizationRole" : never : never, z.ZodObject<RoleShape<import("./AuthorizationSchema").ResolveAuthorizationSchema<O>> extends infer T_2 ? { -readonly [P in keyof T_2]: T_2[P]; } : never, z.core.$strip>> & {
15
+ readonly primaryKey: Extract<keyof z.core.$InferObjectOutput<RoleShape<import("./AuthorizationSchema").ResolveAuthorizationSchema<O>> extends infer T_2 ? { -readonly [P in keyof T_2]: T_2[P]; } : never, {}>, string>;
16
+ } & {
17
+ readonly primaryKey: [["role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never] extends [null | undefined] ? undefined : "fields" extends keyof NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never> ? NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never>[keyof NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never> & "fields"] : undefined] extends [null | undefined] ? "id" : "id" extends infer T_3 ? T_3 extends "id" ? T_3 extends keyof NonNullable<["role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never] extends [null | undefined] ? undefined : "fields" extends keyof NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never> ? NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never>[keyof NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never> & "fields"] : undefined> ? Exclude<NonNullable<["role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never] extends [null | undefined] ? undefined : "fields" extends keyof NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never> ? NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never>[keyof NonNullable<"role" extends infer T ? T extends "role" ? T extends keyof O ? O[T] : undefined : never : never> & "fields"] : undefined>[T_3], undefined> extends infer Value ? [Value] extends [never] ? "id" : Value extends string ? Value : "id" : "id" : "id" : never : never;
18
+ };
19
+ readonly permission: import("@gasboost/table").TableDefinition<["permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never] extends [null | undefined] ? "authorizationPermission" : "modelName" extends infer T_5 ? T_5 extends "modelName" ? T_5 extends keyof NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never> ? Exclude<NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never>[T_5], undefined> extends infer Value ? [Value] extends [never] ? "authorizationPermission" : Value extends string ? Value : "authorizationPermission" : "authorizationPermission" : "authorizationPermission" : never : never, z.ZodObject<PermissionShape<import("./AuthorizationSchema").ResolveAuthorizationSchema<O>> extends infer T_6 ? { -readonly [P in keyof T_6]: T_6[P]; } : never, z.core.$strip>> & {
20
+ readonly primaryKey: Extract<keyof z.core.$InferObjectOutput<PermissionShape<import("./AuthorizationSchema").ResolveAuthorizationSchema<O>> extends infer T_6 ? { -readonly [P in keyof T_6]: T_6[P]; } : never, {}>, string>;
21
+ } & {
22
+ readonly primaryKey: [["permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never] extends [null | undefined] ? undefined : "fields" extends keyof NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never> ? NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never>[keyof NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never> & "fields"] : undefined] extends [null | undefined] ? "id" : "id" extends infer T_7 ? T_7 extends "id" ? T_7 extends keyof NonNullable<["permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never] extends [null | undefined] ? undefined : "fields" extends keyof NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never> ? NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never>[keyof NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never> & "fields"] : undefined> ? Exclude<NonNullable<["permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never] extends [null | undefined] ? undefined : "fields" extends keyof NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never> ? NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never>[keyof NonNullable<"permission" extends infer T_4 ? T_4 extends "permission" ? T_4 extends keyof O ? O[T_4] : undefined : never : never> & "fields"] : undefined>[T_7], undefined> extends infer Value ? [Value] extends [never] ? "id" : Value extends string ? Value : "id" : "id" : "id" : never : never;
23
+ };
24
+ };
25
+ export {};
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAuthorizationTables = createAuthorizationTables;
4
+ const zod_1 = require("zod");
5
+ const AuthorizationSchema_1 = require("./AuthorizationSchema");
6
+ function ensureUniqueFieldNames(modelName, fields) {
7
+ const fieldNames = Object.values(fields);
8
+ if (new Set(fieldNames).size !== fieldNames.length) {
9
+ throw new Error(`Field names for '${modelName}' must be unique.`);
10
+ }
11
+ }
12
+ function keyedTable(definition) {
13
+ return definition;
14
+ }
15
+ function createAuthorizationTables(options = {}) {
16
+ const schema = (0, AuthorizationSchema_1.resolveAuthorizationSchema)(options);
17
+ ensureUniqueFieldNames(schema.role.modelName, schema.role.fields);
18
+ ensureUniqueFieldNames(schema.permission.modelName, schema.permission.fields);
19
+ const roleSchema = zod_1.z.object({
20
+ [schema.role.fields.id]: zod_1.z.string(),
21
+ [schema.role.fields.userId]: zod_1.z.string(),
22
+ [schema.role.fields.role]: zod_1.z.string(),
23
+ });
24
+ const permissionSchema = zod_1.z.object({
25
+ [schema.permission.fields.id]: zod_1.z.string(),
26
+ [schema.permission.fields.userId]: zod_1.z.string(),
27
+ [schema.permission.fields.permission]: zod_1.z.string(),
28
+ [schema.permission.fields.effect]: zod_1.z.enum(["allow", "deny"]),
29
+ });
30
+ return {
31
+ schema,
32
+ role: keyedTable({
33
+ name: schema.role.modelName,
34
+ schema: roleSchema,
35
+ primaryKey: schema.role.fields.id,
36
+ }),
37
+ permission: keyedTable({
38
+ name: schema.permission.modelName,
39
+ schema: permissionSchema,
40
+ primaryKey: schema.permission.fields.id,
41
+ }),
42
+ };
43
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gasboost/auth",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Modern authentication for Google Apps Script with email/password, Apps Script authentication, sessions, and password reset.",
5
5
  "keywords": [
6
6
  "google-apps-script",
@@ -25,6 +25,10 @@
25
25
  ".": {
26
26
  "default": "./dist/index.js",
27
27
  "types": "./dist/index.d.ts"
28
+ },
29
+ "./authorization": {
30
+ "default": "./dist/authorization/index.js",
31
+ "types": "./dist/authorization/index.d.ts"
28
32
  }
29
33
  },
30
34
  "repository": {