@gasboost/auth 0.1.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.
Files changed (68) hide show
  1. package/README.md +484 -0
  2. package/dist/AppsScriptAuth.d.ts +51 -0
  3. package/dist/AppsScriptAuth.js +77 -0
  4. package/dist/AuthPattern.d.ts +5 -0
  5. package/dist/AuthPattern.js +4 -0
  6. package/dist/api/AppsScriptAuthPassword.d.ts +30 -0
  7. package/dist/api/AppsScriptAuthPassword.js +64 -0
  8. package/dist/api/AppsScriptAuthSession.d.ts +10 -0
  9. package/dist/api/AppsScriptAuthSession.js +17 -0
  10. package/dist/api/AppsScriptAuthSignIn.d.ts +20 -0
  11. package/dist/api/AppsScriptAuthSignIn.js +34 -0
  12. package/dist/api/AppsScriptAuthSignOut.d.ts +7 -0
  13. package/dist/api/AppsScriptAuthSignOut.js +9 -0
  14. package/dist/api/AppsScriptAuthSignUp.d.ts +20 -0
  15. package/dist/api/AppsScriptAuthSignUp.js +35 -0
  16. package/dist/api/SignIn.d.ts +19 -0
  17. package/dist/api/SignIn.js +26 -0
  18. package/dist/api/SignUp.d.ts +20 -0
  19. package/dist/api/SignUp.js +25 -0
  20. package/dist/authentication/AppsScriptAuthentication.d.ts +24 -0
  21. package/dist/authentication/AppsScriptAuthentication.js +47 -0
  22. package/dist/authentication/Authentication.d.ts +4 -0
  23. package/dist/authentication/Authentication.js +1 -0
  24. package/dist/authentication/EmailPasswordAuthentication.d.ts +42 -0
  25. package/dist/authentication/EmailPasswordAuthentication.js +75 -0
  26. package/dist/domain/Account.d.ts +11 -0
  27. package/dist/domain/Account.js +10 -0
  28. package/dist/domain/Errors.d.ts +3 -0
  29. package/dist/domain/Errors.js +5 -0
  30. package/dist/domain/Password.d.ts +15 -0
  31. package/dist/domain/Password.js +54 -0
  32. package/dist/domain/PasswordCredential.d.ts +25 -0
  33. package/dist/domain/PasswordCredential.js +57 -0
  34. package/dist/domain/PasswordReset.d.ts +25 -0
  35. package/dist/domain/PasswordReset.js +44 -0
  36. package/dist/domain/PasswordResetToken.d.ts +6 -0
  37. package/dist/domain/PasswordResetToken.js +17 -0
  38. package/dist/domain/Session.d.ts +14 -0
  39. package/dist/domain/Session.js +15 -0
  40. package/dist/domain/User.d.ts +13 -0
  41. package/dist/domain/User.js +13 -0
  42. package/dist/factory/sessionStorageFactory.d.ts +6 -0
  43. package/dist/factory/sessionStorageFactory.js +11 -0
  44. package/dist/identity/AppsScriptIdentity.d.ts +8 -0
  45. package/dist/identity/AppsScriptIdentity.js +8 -0
  46. package/dist/identity/EmailPasswordIdentity.d.ts +13 -0
  47. package/dist/identity/EmailPasswordIdentity.js +19 -0
  48. package/dist/identity/ProviderIdentity.d.ts +5 -0
  49. package/dist/identity/ProviderIdentity.js +1 -0
  50. package/dist/index.d.ts +11 -0
  51. package/dist/index.js +10 -0
  52. package/dist/registration/AppsScriptRegistration.d.ts +13 -0
  53. package/dist/registration/AppsScriptRegistration.js +46 -0
  54. package/dist/registration/EmailPasswordRegistration.d.ts +16 -0
  55. package/dist/registration/EmailPasswordRegistration.js +41 -0
  56. package/dist/registration/Registration.d.ts +4 -0
  57. package/dist/registration/Registration.js +1 -0
  58. package/dist/schema/AuthSchema.d.ts +64 -0
  59. package/dist/schema/AuthSchema.js +35 -0
  60. package/dist/storage/AppsScriptAuthRepository.d.ts +17 -0
  61. package/dist/storage/AppsScriptAuthRepository.js +1 -0
  62. package/dist/storage/AppsScriptCacheSessionStorage.d.ts +10 -0
  63. package/dist/storage/AppsScriptCacheSessionStorage.js +30 -0
  64. package/dist/storage/AppsScriptPropertiesSessionStorage.d.ts +11 -0
  65. package/dist/storage/AppsScriptPropertiesSessionStorage.js +51 -0
  66. package/dist/storage/AppsScriptSessionStorage.d.ts +7 -0
  67. package/dist/storage/AppsScriptSessionStorage.js +1 -0
  68. package/package.json +55 -0
@@ -0,0 +1,25 @@
1
+ export declare class PasswordReset {
2
+ readonly id: string;
3
+ readonly accountId: string;
4
+ readonly tokenHash: string;
5
+ readonly expiresAt: Date;
6
+ readonly enabled: boolean;
7
+ constructor({ id, accountId, tokenHash, expiresAt, enabled, }: {
8
+ id: string;
9
+ accountId: string;
10
+ tokenHash: string;
11
+ expiresAt: Date;
12
+ enabled: boolean;
13
+ });
14
+ static create({ accountId, utilities, expiresAt, }: {
15
+ accountId: string;
16
+ utilities: GoogleAppsScript.Utilities.Utilities;
17
+ expiresAt: Date;
18
+ }): {
19
+ reset: PasswordReset;
20
+ token: string;
21
+ };
22
+ verify(token: string, utilities: GoogleAppsScript.Utilities.Utilities): boolean;
23
+ isExpired(now: Date): boolean;
24
+ disable(): PasswordReset;
25
+ }
@@ -0,0 +1,44 @@
1
+ import { PasswordResetToken } from "./PasswordResetToken";
2
+ export class PasswordReset {
3
+ id;
4
+ accountId;
5
+ tokenHash;
6
+ expiresAt;
7
+ enabled;
8
+ constructor({ id, accountId, tokenHash, expiresAt, enabled, }) {
9
+ this.id = id;
10
+ this.accountId = accountId;
11
+ this.tokenHash = tokenHash;
12
+ this.expiresAt = expiresAt;
13
+ this.enabled = enabled;
14
+ }
15
+ static create({ accountId, utilities, expiresAt, }) {
16
+ const token = PasswordResetToken.generate(utilities);
17
+ return {
18
+ token: token.value,
19
+ reset: new PasswordReset({
20
+ id: utilities.getUuid(),
21
+ accountId,
22
+ tokenHash: token.hash(utilities),
23
+ expiresAt,
24
+ enabled: true,
25
+ }),
26
+ };
27
+ }
28
+ verify(token, utilities) {
29
+ const tokenHash = new PasswordResetToken(token).hash(utilities);
30
+ return tokenHash === this.tokenHash;
31
+ }
32
+ isExpired(now) {
33
+ return this.expiresAt.getTime() <= now.getTime();
34
+ }
35
+ disable() {
36
+ return new PasswordReset({
37
+ id: this.id,
38
+ accountId: this.accountId,
39
+ tokenHash: this.tokenHash,
40
+ expiresAt: this.expiresAt,
41
+ enabled: false,
42
+ });
43
+ }
44
+ }
@@ -0,0 +1,6 @@
1
+ export declare class PasswordResetToken {
2
+ readonly value: string;
3
+ constructor(value: string);
4
+ static generate(utilities: GoogleAppsScript.Utilities.Utilities): PasswordResetToken;
5
+ hash(utilities: GoogleAppsScript.Utilities.Utilities): string;
6
+ }
@@ -0,0 +1,17 @@
1
+ export class PasswordResetToken {
2
+ value;
3
+ constructor(value) {
4
+ this.value = value;
5
+ }
6
+ static generate(utilities) {
7
+ const token = utilities.getUuid();
8
+ return new PasswordResetToken(token);
9
+ }
10
+ hash(utilities) {
11
+ const tokenHash = utilities
12
+ .computeDigest(utilities.DigestAlgorithm.SHA_256, this.value)
13
+ .map((b) => ("00" + (b & 0xff).toString(16)).slice(-2))
14
+ .join("");
15
+ return tokenHash;
16
+ }
17
+ }
@@ -0,0 +1,14 @@
1
+ export type SessionId = string;
2
+ export declare class Session {
3
+ readonly id: SessionId;
4
+ readonly userId: string;
5
+ readonly createdAt: Date;
6
+ readonly expiresAt: Date;
7
+ constructor({ id, userId, createdAt, expiresAt, }: {
8
+ id: SessionId;
9
+ userId: string;
10
+ createdAt: Date;
11
+ expiresAt: Date;
12
+ });
13
+ isExpired(now: Date): boolean;
14
+ }
@@ -0,0 +1,15 @@
1
+ export class Session {
2
+ id;
3
+ userId;
4
+ createdAt;
5
+ expiresAt;
6
+ constructor({ id, userId, createdAt, expiresAt, }) {
7
+ this.id = id;
8
+ this.userId = userId;
9
+ this.createdAt = createdAt;
10
+ this.expiresAt = expiresAt;
11
+ }
12
+ isExpired(now) {
13
+ return now > this.expiresAt;
14
+ }
15
+ }
@@ -0,0 +1,13 @@
1
+ import { AuthPattern } from "../AuthPattern";
2
+ import type { Account } from "./Account";
3
+ export declare class User {
4
+ readonly id: string;
5
+ readonly name: string;
6
+ readonly accounts: Account[];
7
+ constructor({ id, name, accounts, }: {
8
+ id: string;
9
+ name: string;
10
+ accounts: Account[];
11
+ });
12
+ account(provider: AuthPattern): Account | null;
13
+ }
@@ -0,0 +1,13 @@
1
+ export class User {
2
+ id;
3
+ name;
4
+ accounts;
5
+ constructor({ id, name, accounts, }) {
6
+ this.id = id;
7
+ this.name = name;
8
+ this.accounts = accounts;
9
+ }
10
+ account(provider) {
11
+ return (this.accounts.find((account) => account.identity.providerName === provider) || null);
12
+ }
13
+ }
@@ -0,0 +1,6 @@
1
+ import type { AppsScriptSessionStorage } from "../storage/AppsScriptSessionStorage";
2
+ export type SessionStorageType = "properties" | "cache";
3
+ export declare function sessionStorageFactory(storage: SessionStorageType, { cacheService, propertiesService, }: {
4
+ cacheService: GoogleAppsScript.Cache.CacheService;
5
+ propertiesService: GoogleAppsScript.Properties.PropertiesService;
6
+ }): AppsScriptSessionStorage;
@@ -0,0 +1,11 @@
1
+ import { AppsScriptCacheSessionStorage } from "../storage/AppsScriptCacheSessionStorage";
2
+ import { AppsScriptPropertiesSessionStorage } from "../storage/AppsScriptPropertiesSessionStorage";
3
+ export function sessionStorageFactory(storage, { cacheService, propertiesService, }) {
4
+ if (storage === "properties") {
5
+ return new AppsScriptPropertiesSessionStorage(propertiesService.getScriptProperties());
6
+ }
7
+ if (storage === "cache") {
8
+ return new AppsScriptCacheSessionStorage(cacheService.getScriptCache());
9
+ }
10
+ throw new Error("Invalid storage type");
11
+ }
@@ -0,0 +1,8 @@
1
+ import type { ProviderIdentity } from "./ProviderIdentity";
2
+ export declare class AppsScriptIdentity implements ProviderIdentity {
3
+ readonly providerName: "appsScript";
4
+ readonly accountId: string;
5
+ constructor({ googleAccountAddress }: {
6
+ googleAccountAddress: string;
7
+ });
8
+ }
@@ -0,0 +1,8 @@
1
+ import { authPattern } from "../AuthPattern";
2
+ export class AppsScriptIdentity {
3
+ providerName = authPattern.appsScript;
4
+ accountId;
5
+ constructor({ googleAccountAddress }) {
6
+ this.accountId = googleAccountAddress;
7
+ }
8
+ }
@@ -0,0 +1,13 @@
1
+ import type { HashedPassword, Password } from "../domain/Password";
2
+ import type { ProviderIdentity } from "./ProviderIdentity";
3
+ export declare class EmailPasswordIdentity implements ProviderIdentity {
4
+ readonly providerName: "emailPassword";
5
+ readonly accountId: string;
6
+ readonly password: HashedPassword;
7
+ constructor({ accountId, password, }: {
8
+ accountId: string;
9
+ password: HashedPassword;
10
+ });
11
+ verify(password: Password, salt: string): Promise<boolean>;
12
+ changePassword(newPassword: HashedPassword): EmailPasswordIdentity;
13
+ }
@@ -0,0 +1,19 @@
1
+ import { authPattern } from "../AuthPattern";
2
+ export class EmailPasswordIdentity {
3
+ providerName = authPattern.emailPassword;
4
+ accountId;
5
+ password;
6
+ constructor({ accountId, password, }) {
7
+ this.accountId = accountId;
8
+ this.password = password;
9
+ }
10
+ async verify(password, salt) {
11
+ return this.password.verify(password, salt);
12
+ }
13
+ changePassword(newPassword) {
14
+ return new EmailPasswordIdentity({
15
+ accountId: this.accountId,
16
+ password: newPassword,
17
+ });
18
+ }
19
+ }
@@ -0,0 +1,5 @@
1
+ import type { AuthPattern } from "../AuthPattern";
2
+ export interface ProviderIdentity {
3
+ readonly providerName: AuthPattern;
4
+ readonly accountId: string;
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ export { AppsScriptAuth } from "./AppsScriptAuth";
2
+ export type { AppsScriptAuthRepository } from "./storage/AppsScriptAuthRepository";
3
+ export { AuthSchemaConfig, type AuthSchema, type AuthSchemaOptions, } from "./schema/AuthSchema";
4
+ export { authPattern, type AuthPattern } from "./AuthPattern";
5
+ export { Account } from "./domain/Account";
6
+ export { User } from "./domain/User";
7
+ export { HashedPassword, Password } from "./domain/Password";
8
+ export { PasswordCredential } from "./domain/PasswordCredential";
9
+ export { PasswordReset } from "./domain/PasswordReset";
10
+ export { AppsScriptIdentity } from "./identity/AppsScriptIdentity";
11
+ export { EmailPasswordIdentity } from "./identity/EmailPasswordIdentity";
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export { AppsScriptAuth } from "./AppsScriptAuth";
2
+ export { AuthSchemaConfig, } from "./schema/AuthSchema";
3
+ export { authPattern } from "./AuthPattern";
4
+ export { Account } from "./domain/Account";
5
+ export { User } from "./domain/User";
6
+ export { HashedPassword, Password } from "./domain/Password";
7
+ export { PasswordCredential } from "./domain/PasswordCredential";
8
+ export { PasswordReset } from "./domain/PasswordReset";
9
+ export { AppsScriptIdentity } from "./identity/AppsScriptIdentity";
10
+ export { EmailPasswordIdentity } from "./identity/EmailPasswordIdentity";
@@ -0,0 +1,13 @@
1
+ import { User } from "../domain/User";
2
+ import type { AppsScriptAuthRepository } from "../storage/AppsScriptAuthRepository";
3
+ import type { Registration } from "./Registration";
4
+ export interface AppsScriptRegistrationInput {
5
+ readonly name: string;
6
+ }
7
+ export declare class AppsScriptRegistration implements Registration<AppsScriptRegistrationInput> {
8
+ private readonly utilities;
9
+ private readonly session;
10
+ private readonly repository;
11
+ constructor(utilities: GoogleAppsScript.Utilities.Utilities, session: GoogleAppsScript.Base.Session, repository: AppsScriptAuthRepository);
12
+ register(input: AppsScriptRegistrationInput): Promise<User>;
13
+ }
@@ -0,0 +1,46 @@
1
+ import { authPattern } from "../AuthPattern";
2
+ import { Account } from "../domain/Account";
3
+ import { User } from "../domain/User";
4
+ import { AppsScriptIdentity } from "../identity/AppsScriptIdentity";
5
+ export class AppsScriptRegistration {
6
+ utilities;
7
+ session;
8
+ repository;
9
+ constructor(utilities, session, repository) {
10
+ this.utilities = utilities;
11
+ this.session = session;
12
+ this.repository = repository;
13
+ }
14
+ async register(input) {
15
+ // Session.getActiveUser() から識別子取得
16
+ const email = this.session.getActiveUser().getEmail();
17
+ if (!email) {
18
+ throw new Error("No active user found");
19
+ }
20
+ const existingAccount = await this.repository.account.findByIdentity(authPattern.appsScript, email);
21
+ if (existingAccount) {
22
+ throw new Error("Account already registered");
23
+ }
24
+ // AppsScriptIdentity作成
25
+ const appsScriptIdentity = new AppsScriptIdentity({
26
+ googleAccountAddress: email,
27
+ });
28
+ const userId = this.utilities.getUuid();
29
+ // Account作成
30
+ const account = new Account({
31
+ id: this.utilities.getUuid(),
32
+ userId: userId,
33
+ identity: appsScriptIdentity,
34
+ });
35
+ // User作成
36
+ const user = new User({
37
+ id: userId,
38
+ name: input.name,
39
+ accounts: [account],
40
+ });
41
+ // 永続化
42
+ await this.repository.user.create(user);
43
+ // User返却
44
+ return user;
45
+ }
46
+ }
@@ -0,0 +1,16 @@
1
+ import type { EmailPasswordAuthConfig } from "../authentication/EmailPasswordAuthentication";
2
+ import { User } from "../domain/User";
3
+ import type { AppsScriptAuthRepository } from "../storage/AppsScriptAuthRepository";
4
+ import type { Registration } from "./Registration";
5
+ export interface EmailPasswordRegistrationInput {
6
+ readonly name: string;
7
+ readonly email: string;
8
+ readonly password: string;
9
+ }
10
+ export declare class EmailPasswordRegistration implements Registration<EmailPasswordRegistrationInput> {
11
+ private readonly repository;
12
+ private readonly utilities;
13
+ private readonly config;
14
+ constructor(repository: AppsScriptAuthRepository, utilities: GoogleAppsScript.Utilities.Utilities, config: EmailPasswordAuthConfig);
15
+ register(input: EmailPasswordRegistrationInput): Promise<User>;
16
+ }
@@ -0,0 +1,41 @@
1
+ import { authPattern } from "../AuthPattern";
2
+ import { Account } from "../domain/Account";
3
+ import { Password } from "../domain/Password";
4
+ import { User } from "../domain/User";
5
+ import { EmailPasswordIdentity } from "../identity/EmailPasswordIdentity";
6
+ export class EmailPasswordRegistration {
7
+ repository;
8
+ utilities;
9
+ config;
10
+ constructor(repository, utilities, config) {
11
+ this.repository = repository;
12
+ this.utilities = utilities;
13
+ this.config = config;
14
+ }
15
+ async register(input) {
16
+ const existingAccount = await this.repository.account.findByIdentity(authPattern.emailPassword, input.email);
17
+ if (existingAccount) {
18
+ throw new Error("Account already registered");
19
+ }
20
+ const userId = this.utilities.getUuid();
21
+ const accountId = this.utilities.getUuid();
22
+ const password = new Password(input.password, this.utilities, this.config.pepper, this.config.iterations);
23
+ const hashedPassword = await password.hash(accountId);
24
+ const identity = new EmailPasswordIdentity({
25
+ accountId: input.email,
26
+ password: hashedPassword,
27
+ });
28
+ const account = new Account({
29
+ id: accountId,
30
+ userId,
31
+ identity,
32
+ });
33
+ const user = new User({
34
+ id: userId,
35
+ name: input.name,
36
+ accounts: [account],
37
+ });
38
+ await this.repository.user.create(user);
39
+ return user;
40
+ }
41
+ }
@@ -0,0 +1,4 @@
1
+ import { User } from "../domain/User";
2
+ export interface Registration<T> {
3
+ register(input: T): Promise<User>;
4
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,64 @@
1
+ export type AuthSchemaOptions = {
2
+ dbId: string;
3
+ user?: {
4
+ modelName?: string;
5
+ fields?: {
6
+ id?: string;
7
+ name?: string;
8
+ };
9
+ };
10
+ account?: {
11
+ modelName?: string;
12
+ fields?: {
13
+ id?: string;
14
+ userId?: string;
15
+ provider?: string;
16
+ providerAccountId?: string;
17
+ passwordHash?: string;
18
+ };
19
+ };
20
+ passwordReset?: {
21
+ modelName?: string;
22
+ fields?: {
23
+ id?: string;
24
+ accountId?: string;
25
+ tokenHash?: string;
26
+ expiresAt?: string;
27
+ enabled?: string;
28
+ };
29
+ };
30
+ };
31
+ export type AuthSchema = {
32
+ dbId: string;
33
+ user: {
34
+ modelName: string;
35
+ fields: {
36
+ id: string;
37
+ name: string;
38
+ };
39
+ };
40
+ account: {
41
+ modelName: string;
42
+ fields: {
43
+ id: string;
44
+ userId: string;
45
+ provider: string;
46
+ providerAccountId: string;
47
+ passwordHash: string;
48
+ };
49
+ };
50
+ passwordReset: {
51
+ modelName: string;
52
+ fields: {
53
+ id: string;
54
+ accountId: string;
55
+ tokenHash: string;
56
+ expiresAt: string;
57
+ enabled: string;
58
+ };
59
+ };
60
+ };
61
+ export declare class AuthSchemaConfig {
62
+ readonly schema: AuthSchema;
63
+ constructor(options?: AuthSchemaOptions);
64
+ }
@@ -0,0 +1,35 @@
1
+ export class AuthSchemaConfig {
2
+ schema;
3
+ constructor(options = { dbId: "" }) {
4
+ this.schema = {
5
+ dbId: options.dbId,
6
+ user: {
7
+ modelName: options.user?.modelName ?? "user",
8
+ fields: {
9
+ id: options.user?.fields?.id ?? "id",
10
+ name: options.user?.fields?.name ?? "name",
11
+ },
12
+ },
13
+ account: {
14
+ modelName: options.account?.modelName ?? "account",
15
+ fields: {
16
+ id: options.account?.fields?.id ?? "id",
17
+ userId: options.account?.fields?.userId ?? "userId",
18
+ provider: options.account?.fields?.provider ?? "provider",
19
+ providerAccountId: options.account?.fields?.providerAccountId ?? "providerAccountId",
20
+ passwordHash: options.account?.fields?.passwordHash ?? "passwordHash",
21
+ },
22
+ },
23
+ passwordReset: {
24
+ modelName: options.passwordReset?.modelName ?? "passwordReset",
25
+ fields: {
26
+ id: options.passwordReset?.fields?.id ?? "id",
27
+ accountId: options.passwordReset?.fields?.accountId ?? "accountId",
28
+ tokenHash: options.passwordReset?.fields?.tokenHash ?? "tokenHash",
29
+ expiresAt: options.passwordReset?.fields?.expiresAt ?? "expiresAt",
30
+ enabled: options.passwordReset?.fields?.enabled ?? "enabled",
31
+ },
32
+ },
33
+ };
34
+ }
35
+ }
@@ -0,0 +1,17 @@
1
+ import type { AuthPattern } from "../AuthPattern";
2
+ import { Account } from "../domain/Account";
3
+ import type { PasswordCredential } from "../domain/PasswordCredential";
4
+ import type { User } from "../domain/User";
5
+ export interface AppsScriptAuthRepository {
6
+ account: {
7
+ findByIdentity(provider: AuthPattern, identifier: string): Promise<Account | null>;
8
+ };
9
+ user: {
10
+ find: (id: string) => Promise<User | null>;
11
+ create: (user: User) => Promise<User>;
12
+ };
13
+ passwordCredential: {
14
+ findByResetTokenHash(tokenHash: string): Promise<PasswordCredential | null>;
15
+ save(credential: PasswordCredential): Promise<void>;
16
+ };
17
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import { Session, type SessionId } from "../domain/Session";
2
+ import type { AppsScriptSessionStorage } from "./AppsScriptSessionStorage";
3
+ export declare class AppsScriptCacheSessionStorage implements AppsScriptSessionStorage {
4
+ private readonly storage;
5
+ constructor(storage: GoogleAppsScript.Cache.Cache);
6
+ save(session: Session): Promise<void>;
7
+ get(id: SessionId): Promise<Session | null>;
8
+ delete(id: SessionId): Promise<void>;
9
+ cleanupExpired(): Promise<void>;
10
+ }
@@ -0,0 +1,30 @@
1
+ import { Session } from "../domain/Session";
2
+ export class AppsScriptCacheSessionStorage {
3
+ storage;
4
+ constructor(storage) {
5
+ this.storage = storage;
6
+ }
7
+ async save(session) {
8
+ const expirationInSeconds = Math.floor((session.expiresAt.getTime() - Date.now()) / 1000);
9
+ this.storage.put(session.id, JSON.stringify(session), expirationInSeconds);
10
+ }
11
+ async get(id) {
12
+ const value = this.storage.get(id);
13
+ if (!value) {
14
+ return null;
15
+ }
16
+ const data = JSON.parse(value);
17
+ return new Session({
18
+ id: data.id,
19
+ userId: data.userId,
20
+ createdAt: new Date(data.createdAt),
21
+ expiresAt: new Date(data.expiresAt),
22
+ });
23
+ }
24
+ async delete(id) {
25
+ this.storage.remove(id);
26
+ }
27
+ async cleanupExpired() {
28
+ // CacheService handles expiration automatically.
29
+ }
30
+ }
@@ -0,0 +1,11 @@
1
+ import { Session, SessionId } from "../domain/Session";
2
+ import type { AppsScriptSessionStorage } from "./AppsScriptSessionStorage";
3
+ export declare class AppsScriptPropertiesSessionStorage implements AppsScriptSessionStorage {
4
+ private readonly storage;
5
+ private readonly prefix;
6
+ constructor(storage: GoogleAppsScript.Properties.Properties);
7
+ save(session: Session): Promise<void>;
8
+ get(id: SessionId): Promise<Session | null>;
9
+ delete(id: SessionId): Promise<void>;
10
+ cleanupExpired(): Promise<void>;
11
+ }
@@ -0,0 +1,51 @@
1
+ import { Session } from "../domain/Session";
2
+ export class AppsScriptPropertiesSessionStorage {
3
+ storage;
4
+ prefix = "session:";
5
+ constructor(storage) {
6
+ this.storage = storage;
7
+ }
8
+ async save(session) {
9
+ this.storage.setProperty(`${this.prefix}${session.id}`, JSON.stringify(session));
10
+ }
11
+ async get(id) {
12
+ const value = this.storage.getProperty(`${this.prefix}${id}`);
13
+ if (!value) {
14
+ return null;
15
+ }
16
+ const stored = JSON.parse(value);
17
+ const session = new Session({
18
+ id: stored.id,
19
+ userId: stored.userId,
20
+ createdAt: new Date(stored.createdAt),
21
+ expiresAt: new Date(stored.expiresAt),
22
+ });
23
+ if (session.expiresAt.getTime() <= Date.now()) {
24
+ this.storage.deleteProperty(`${this.prefix}${id}`);
25
+ return null;
26
+ }
27
+ return session;
28
+ }
29
+ async delete(id) {
30
+ this.storage.deleteProperty(`${this.prefix}${id}`);
31
+ }
32
+ async cleanupExpired() {
33
+ const properties = this.storage.getProperties();
34
+ const now = new Date();
35
+ for (const [key, value] of Object.entries(properties)) {
36
+ if (!key.startsWith(this.prefix)) {
37
+ continue;
38
+ }
39
+ const sessionData = JSON.parse(value);
40
+ const session = new Session({
41
+ id: sessionData.id,
42
+ userId: sessionData.userId,
43
+ createdAt: new Date(sessionData.createdAt),
44
+ expiresAt: new Date(sessionData.expiresAt),
45
+ });
46
+ if (session.isExpired(now)) {
47
+ this.storage.deleteProperty(key);
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,7 @@
1
+ import type { Session, SessionId } from "../domain/Session";
2
+ export interface AppsScriptSessionStorage {
3
+ save(session: Session): Promise<void>;
4
+ get(id: SessionId): Promise<Session | null>;
5
+ delete(id: SessionId): Promise<void>;
6
+ cleanupExpired(): Promise<void>;
7
+ }
@@ -0,0 +1 @@
1
+ export {};