@polyester/sdk 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/README.md +63 -17
- package/dist/account-signer/types.d.ts.map +1 -1
- package/dist/account-signer/types.js +6 -3
- package/dist/account-signer/types.js.map +1 -1
- package/dist/browser-client.d.ts +4 -2
- package/dist/browser-client.d.ts.map +1 -1
- package/dist/browser-client.js +3 -4
- package/dist/browser-client.js.map +1 -1
- package/dist/catalogs/client-catalog.d.ts.map +1 -1
- package/dist/catalogs/client-catalog.js +11 -4
- package/dist/catalogs/client-catalog.js.map +1 -1
- package/dist/catalogs/index.js +1 -1
- package/dist/catalogs/readers.d.ts.map +1 -1
- package/dist/catalogs/readers.js +3 -1
- package/dist/catalogs/readers.js.map +1 -1
- package/dist/catalogs/snapshot-validation.js +132 -0
- package/dist/catalogs/snapshot-validation.js.map +1 -0
- package/dist/catalogs/snapshot.d.ts.map +1 -1
- package/dist/catalogs/snapshot.js +16 -7
- package/dist/catalogs/snapshot.js.map +1 -1
- package/dist/catalogs/zipper-supply.d.ts.map +1 -1
- package/dist/catalogs/zipper-supply.js +10 -7
- package/dist/catalogs/zipper-supply.js.map +1 -1
- package/dist/core-client.d.ts +24 -17
- package/dist/core-client.d.ts.map +1 -1
- package/dist/core-client.js +21 -3
- package/dist/core-client.js.map +1 -1
- package/dist/environment.d.ts.map +1 -1
- package/dist/environment.js +32 -1
- package/dist/environment.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/realtime/client.js +13 -2
- package/dist/realtime/client.js.map +1 -1
- package/dist/realtime/snapshot-then-stream.js +1 -1
- package/dist/realtime/snapshot-then-stream.js.map +1 -1
- package/dist/realtime/types.d.ts +2 -0
- package/dist/realtime/types.d.ts.map +1 -1
- package/dist/server-client.d.ts +17 -8
- package/dist/server-client.d.ts.map +1 -1
- package/dist/server-client.js +8 -11
- package/dist/server-client.js.map +1 -1
- package/dist/services/accounts/accounts.js +3 -3
- package/dist/services/accounts/accounts.js.map +1 -1
- package/dist/services/address-book/address-book.js +28 -28
- package/dist/services/address-book/address-book.js.map +1 -1
- package/dist/services/address-book/address-book.schemas.d.ts.map +1 -1
- package/dist/services/address-book/address-book.schemas.js +2 -1
- package/dist/services/address-book/address-book.schemas.js.map +1 -1
- package/dist/services/api-keys/api-keys.d.ts.map +1 -1
- package/dist/services/api-keys/api-keys.js +12 -12
- package/dist/services/api-keys/api-keys.js.map +1 -1
- package/dist/services/auth/auth.d.ts +9 -3
- package/dist/services/auth/auth.d.ts.map +1 -1
- package/dist/services/auth/auth.js +11 -7
- package/dist/services/auth/auth.js.map +1 -1
- package/dist/services/auth/profile/profile.d.ts.map +1 -1
- package/dist/services/auth/profile/profile.js +7 -6
- package/dist/services/auth/profile/profile.js.map +1 -1
- package/dist/services/auth/session.d.ts +1 -1
- package/dist/services/auth/session.d.ts.map +1 -1
- package/dist/services/auth/session.js +6 -2
- package/dist/services/auth/session.js.map +1 -1
- package/dist/services/auth/session.types.d.ts +3 -2
- package/dist/services/auth/session.types.d.ts.map +1 -1
- package/dist/services/balances/balances.d.ts +1 -1
- package/dist/services/balances/balances.d.ts.map +1 -1
- package/dist/services/balances/balances.js +9 -8
- package/dist/services/balances/balances.js.map +1 -1
- package/dist/services/balances/balances.schemas.d.ts +1 -1
- package/dist/services/balances/balances.schemas.d.ts.map +1 -1
- package/dist/services/balances/balances.schemas.js +1 -1
- package/dist/services/balances/balances.schemas.js.map +1 -1
- package/dist/services/candles/candles.d.ts.map +1 -1
- package/dist/services/candles/candles.js +10 -9
- package/dist/services/candles/candles.js.map +1 -1
- package/dist/services/candles/candles.schemas.d.ts +11 -11
- package/dist/services/candles/candles.schemas.d.ts.map +1 -1
- package/dist/services/candles/candles.schemas.js +1 -2
- package/dist/services/candles/candles.schemas.js.map +1 -1
- package/dist/services/chain-analytics/chain-analytics.js +7 -7
- package/dist/services/chain-analytics/chain-analytics.js.map +1 -1
- package/dist/services/deposit/deposit.js +5 -5
- package/dist/services/deposit/deposit.js.map +1 -1
- package/dist/services/guard-signer/guard-signer.js +13 -13
- package/dist/services/guard-signer/guard-signer.js.map +1 -1
- package/dist/services/heatmap/heatmap.d.ts.map +1 -1
- package/dist/services/heatmap/heatmap.js +6 -5
- package/dist/services/heatmap/heatmap.js.map +1 -1
- package/dist/services/heatmap/heatmap.schemas.d.ts +17 -17
- package/dist/services/heatmap/heatmap.schemas.js +1 -1
- package/dist/services/heatmap/heatmap.schemas.js.map +1 -1
- package/dist/services/internal-transfers/internal-transfers.js +3 -3
- package/dist/services/internal-transfers/internal-transfers.js.map +1 -1
- package/dist/services/lifecycle/lifecycle.d.ts.map +1 -1
- package/dist/services/lifecycle/lifecycle.js +9 -8
- package/dist/services/lifecycle/lifecycle.js.map +1 -1
- package/dist/services/market-data/market-data.d.ts.map +1 -1
- package/dist/services/market-data/market-data.js +6 -5
- package/dist/services/market-data/market-data.js.map +1 -1
- package/dist/services/market-data/market-data.schemas.d.ts +2 -2
- package/dist/services/market-data/market-data.schemas.d.ts.map +1 -1
- package/dist/services/market-data/market-data.schemas.js +2 -6
- package/dist/services/market-data/market-data.schemas.js.map +1 -1
- package/dist/services/market-overview/market-overview.d.ts.map +1 -1
- package/dist/services/market-overview/market-overview.js +4 -3
- package/dist/services/market-overview/market-overview.js.map +1 -1
- package/dist/services/market-overview/market-overview.schemas.d.ts +3 -3
- package/dist/services/mfa/mfa.js +27 -27
- package/dist/services/mfa/mfa.js.map +1 -1
- package/dist/services/orderbook/orderbook.d.ts.map +1 -1
- package/dist/services/orderbook/orderbook.js +5 -4
- package/dist/services/orderbook/orderbook.js.map +1 -1
- package/dist/services/orderbook/orderbook.schemas.d.ts +1 -1
- package/dist/services/orders/orders-batch.schemas.d.ts +14 -14
- package/dist/services/orders/orders-batch.schemas.js +1 -1
- package/dist/services/orders/orders-input.schemas.d.ts +13 -4
- package/dist/services/orders/orders-input.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-input.schemas.js +8 -4
- package/dist/services/orders/orders-input.schemas.js.map +1 -1
- package/dist/services/orders/orders-modify.schemas.d.ts +22 -3
- package/dist/services/orders/orders-modify.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-modify.schemas.js +7 -3
- package/dist/services/orders/orders-modify.schemas.js.map +1 -1
- package/dist/services/orders/orders-output.schemas.d.ts +12 -12
- package/dist/services/orders/orders.d.ts +2 -2
- package/dist/services/orders/orders.d.ts.map +1 -1
- package/dist/services/orders/orders.js +44 -31
- package/dist/services/orders/orders.js.map +1 -1
- package/dist/services/policies/api-key-policies/api-key-policies.d.ts.map +1 -1
- package/dist/services/policies/api-key-policies/api-key-policies.js +11 -11
- package/dist/services/policies/api-key-policies/api-key-policies.js.map +1 -1
- package/dist/services/policies/subaccount-policies/subaccount-policies.d.ts.map +1 -1
- package/dist/services/policies/subaccount-policies/subaccount-policies.js +13 -12
- package/dist/services/policies/subaccount-policies/subaccount-policies.js.map +1 -1
- package/dist/services/social-verification/social-verification.d.ts.map +1 -1
- package/dist/services/social-verification/social-verification.js +7 -7
- package/dist/services/social-verification/social-verification.js.map +1 -1
- package/dist/services/subaccount-resolver.js +5 -3
- package/dist/services/subaccount-resolver.js.map +1 -1
- package/dist/services/subaccounts/subaccounts.d.ts +1 -1
- package/dist/services/subaccounts/subaccounts.d.ts.map +1 -1
- package/dist/services/subaccounts/subaccounts.js +34 -33
- package/dist/services/subaccounts/subaccounts.js.map +1 -1
- package/dist/services/subaccounts/subaccounts.schemas.d.ts +2 -2
- package/dist/services/subaccounts/subaccounts.schemas.js +1 -1
- package/dist/services/subaccounts/subaccounts.schemas.js.map +1 -1
- package/dist/services/trades/trades.d.ts.map +1 -1
- package/dist/services/trades/trades.js +5 -4
- package/dist/services/trades/trades.js.map +1 -1
- package/dist/services/trading-withdraws/trading-withdraws.js +8 -8
- package/dist/services/trading-withdraws/trading-withdraws.js.map +1 -1
- package/dist/services/transfers/transfers.d.ts +1 -1
- package/dist/services/transfers/transfers.d.ts.map +1 -1
- package/dist/services/transfers/transfers.js +5 -4
- package/dist/services/transfers/transfers.js.map +1 -1
- package/dist/services/triggers/trigger-input.schemas.d.ts +1 -1
- package/dist/services/triggers/triggers-output.schemas.d.ts +1 -1
- package/dist/services/triggers/triggers.d.ts.map +1 -1
- package/dist/services/triggers/triggers.js +21 -20
- package/dist/services/triggers/triggers.js.map +1 -1
- package/dist/services/whiteboard/whiteboard.js +15 -15
- package/dist/services/whiteboard/whiteboard.js.map +1 -1
- package/dist/services/zipper/zipper.js +3 -3
- package/dist/services/zipper/zipper.js.map +1 -1
- package/dist/shared/connect-error-mapping.d.ts +1 -1
- package/dist/shared/connect-error-mapping.js +27 -1
- package/dist/shared/connect-error-mapping.js.map +1 -1
- package/dist/shared/transports.js +7 -12
- package/dist/shared/transports.js.map +1 -1
- package/dist/shared/types.d.ts +12 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/validation.js +19 -0
- package/dist/shared/validation.js.map +1 -0
- package/dist/utils/cookies.d.ts +8 -3
- package/dist/utils/cookies.d.ts.map +1 -1
- package/dist/utils/cookies.js +7 -1
- package/dist/utils/cookies.js.map +1 -1
- package/dist/utils/event-emitter.d.ts +1 -1
- package/dist/utils/event-emitter.d.ts.map +1 -1
- package/dist/utils/event-emitter.js +4 -2
- package/dist/utils/event-emitter.js.map +1 -1
- package/dist/utils/evm.js +2 -2
- package/dist/utils/evm.js.map +1 -1
- package/dist/utils/jwt.d.ts +2 -2
- package/dist/utils/jwt.d.ts.map +1 -1
- package/dist/utils/jwt.js +2 -2
- package/dist/utils/jwt.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect-error-mapping.js","names":["OrderErrorDetailSchema"],"sources":["../../src/shared/connect-error-mapping.ts"],"sourcesContent":["import { Code, ConnectError, type Interceptor } from \"@connectrpc/connect\";\nimport * as v from \"valibot\";\nimport { AuthErrorCode, AuthErrorDetailSchema } from \"../gen/auth/v1/auth_pb.js\";\nimport {\n ErrorCode as OrderErrorCode,\n ErrorDetailSchema as OrderErrorDetailSchema,\n} from \"../gen/orders/v1/orders_pb.js\";\nimport {\n AlreadyExistsError,\n AuthenticationError,\n InternalServerError,\n isAbortError,\n MfaEnrollmentRequiredError,\n MfaLastFactorRequiredError,\n MfaVerificationError,\n type MfaVerificationFailureReason,\n normalizeErrorMessage,\n PermissionError,\n PolicyInUseError,\n PolicyLockedError,\n PolicyScopeMismatchError,\n PolyesterError,\n type PolyesterErrorOptions,\n PreconditionFailedError,\n RateLimitError,\n ResourceNotFoundError,\n RevisionConflictError,\n ServiceUnavailableError,\n SessionElevationRequiredError,\n StaleQuoteError,\n StepUpRequiredError,\n TimeoutError,\n TransientError,\n ValidationError,\n} from \"./errors.js\";\nimport { RateLimitDetailSchema, type RateLimitDetail } from \"./rate-limit.schemas.js\";\n\nfunction getAuthErrorDetails(err: unknown) {\n return ConnectError.from(err).findDetails(AuthErrorDetailSchema);\n}\n\nfunction hasAuthErrorCode(err: unknown, code: AuthErrorCode): boolean {\n return getAuthErrorDetails(err).some((detail) => detail.code === code);\n}\n\nfunction hasOrderErrorCode(err: unknown, code: OrderErrorCode): boolean {\n return getOrderErrorDetails(err).some((detail) => detail.code === code);\n}\n\nfunction getOrderErrorDetails(err: unknown) {\n return ConnectError.from(err).findDetails(OrderErrorDetailSchema);\n}\n\nfunction getRateLimitDetail(err: unknown): RateLimitDetail | undefined {\n for (const orderDetail of getOrderErrorDetails(err)) {\n if (!orderDetail.rateLimit) continue;\n const result = v.safeParse(RateLimitDetailSchema, orderDetail.rateLimit);\n if (result.success) return result.output;\n }\n return undefined;\n}\n\nfunction safeRetryAfterMs(rateLimit: RateLimitDetail | undefined): number | undefined {\n if (rateLimit?.retryAfterMs === undefined) return undefined;\n const value = BigInt(rateLimit.retryAfterMs);\n return value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : undefined;\n}\n\n/**\n * Returns the error message without the leading \"[code] \" prefix that\n * `ConnectError` prepends, e.g. \"[invalid_argument] Insufficient funds.\"\n * becomes \"Insufficient funds.\".\n */\nexport function getNormalizedConnectMessage(err: unknown): string {\n const ce = ConnectError.from(err);\n const raw = ce.message ?? \"\";\n return normalizeErrorMessage(raw);\n}\n\nexport type MfaErrorKind = \"session-elevation\" | \"enrollment\" | \"step-up\";\n\n/**\n * Classifies an error as one of the MFA flows the backend can demand.\n * Classification is based only on stable structured auth error details.\n */\nexport function detectMfaErrorKind(err: unknown): MfaErrorKind | null {\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_ELEVATION_REQUIRED)) {\n return \"session-elevation\";\n }\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_STEP_UP_REQUIRED)) return \"step-up\";\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_NOT_ENROLLED)) return \"enrollment\";\n return null;\n}\n\nfunction parseRetryAfterMs(ce: ConnectError): number | undefined {\n const value = ce.metadata.get(\"retry-after\");\n if (!value) return undefined;\n const seconds = Number(value);\n if (Number.isFinite(seconds)) return Math.max(0, Math.round(seconds * 1000));\n const date = Date.parse(value);\n if (!Number.isNaN(date)) return Math.max(0, date - Date.now());\n return undefined;\n}\n\nconst MFA_ERROR_CLASSES = {\n \"session-elevation\": SessionElevationRequiredError,\n enrollment: MfaEnrollmentRequiredError,\n \"step-up\": StepUpRequiredError,\n} as const;\n\n/**\n * Maps a `ConnectError` from the Polyester backend onto the typed\n * {@link PolyesterError} tree. The original error is preserved as `cause`.\n */\nexport function connectErrorToPolyesterError(ce: ConnectError): PolyesterError {\n const message = getNormalizedConnectMessage(ce);\n const options: PolyesterErrorOptions = { cause: ce };\n const withFallback = (fallback: string) => message || fallback;\n\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_RESOURCE_NOT_FOUND)) {\n return new ResourceNotFoundError(withFallback(\"Resource not found.\"), options);\n }\n\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_REVISION_CONFLICT)) {\n return new RevisionConflictError(\n withFallback(\"Resource changed since it was last read.\"),\n options,\n );\n }\n\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_POLICY_IN_USE)) {\n return new PolicyInUseError(withFallback(\"Policy is still in use.\"), options);\n }\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_POLICY_LOCKED)) {\n return new PolicyLockedError(withFallback(\"Policy is locked.\"), options);\n }\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_POLICY_SCOPE_MISMATCH)) {\n return new PolicyScopeMismatchError(\n withFallback(\"Policy does not belong to the target account scope.\"),\n options,\n );\n }\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_MFA_LAST_FACTOR_REQUIRED)) {\n return new MfaLastFactorRequiredError(\n withFallback(\"At least one active MFA factor must remain enrolled.\"),\n options,\n );\n }\n\n const mfaVerificationReason = getMfaVerificationFailureReason(ce);\n if (mfaVerificationReason) {\n return new MfaVerificationError(\n withFallback(\"MFA verification failed.\"),\n mfaVerificationReason,\n options,\n );\n }\n\n const mfaKind = detectMfaErrorKind(ce);\n if (mfaKind) {\n return new MFA_ERROR_CLASSES[mfaKind](\n withFallback(\"Multi-factor authentication required.\"),\n options,\n );\n }\n\n if (hasOrderErrorCode(ce, OrderErrorCode.STALE_QUOTE)) {\n return new StaleQuoteError(withFallback(\"The submitted market quote is stale.\"), options);\n }\n\n const rateLimit = getRateLimitDetail(ce);\n if (rateLimit || hasOrderErrorCode(ce, OrderErrorCode.RATE_LIMIT_EXCEEDED)) {\n return new RateLimitError(withFallback(\"Rate limit exceeded.\"), {\n ...options,\n rateLimit,\n retryAfterMs: safeRetryAfterMs(rateLimit) ?? parseRetryAfterMs(ce),\n });\n }\n\n switch (ce.code) {\n case Code.InvalidArgument:\n case Code.OutOfRange:\n return new ValidationError(withFallback(\"Invalid request.\"), options);\n case Code.NotFound:\n return new ResourceNotFoundError(withFallback(\"Resource not found.\"), options);\n case Code.AlreadyExists:\n return new AlreadyExistsError(withFallback(\"Resource already exists.\"), options);\n case Code.PermissionDenied:\n return new PermissionError(withFallback(\"Permission denied.\"), options);\n case Code.Unauthenticated:\n return new AuthenticationError(withFallback(\"Authentication required.\"), options);\n case Code.FailedPrecondition:\n return new PreconditionFailedError(withFallback(\"Precondition failed.\"), options);\n case Code.ResourceExhausted:\n return new RateLimitError(withFallback(\"Rate limit exceeded.\"), {\n ...options,\n retryAfterMs: parseRetryAfterMs(ce),\n });\n case Code.DeadlineExceeded:\n return new TimeoutError(withFallback(\"Request timed out.\"), options);\n case Code.Unavailable:\n return new ServiceUnavailableError(withFallback(\"Service unavailable.\"), options);\n case Code.Aborted:\n return new TransientError(withFallback(\"Operation aborted by the backend.\"), options);\n default:\n // Gateways sometimes surface outages as Unknown with this stock phrase.\n if (/service temporarily unavailable/i.test(message)) {\n return new ServiceUnavailableError(withFallback(\"Service unavailable.\"), options);\n }\n return new InternalServerError(withFallback(\"Internal server error.\"), options);\n }\n}\n\nfunction getMfaVerificationFailureReason(err: unknown): MfaVerificationFailureReason | null {\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_CHALLENGE_INVALID)) {\n return \"challenge-invalid\";\n }\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_CHALLENGE_LOCKED)) {\n return \"challenge-locked\";\n }\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_OTP_INVALID)) return \"otp-invalid\";\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_RECOVERY_INVALID)) {\n return \"recovery-code-invalid\";\n }\n if (\n hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_PASSKEY_CREDENTIAL_INVALID) ||\n hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_PASSKEY_VERIFY_FAILED)\n ) {\n return \"passkey-invalid\";\n }\n\n return null;\n}\n\nfunction findPolyesterErrorInCauseChain(err: unknown): PolyesterError | null {\n let current: unknown = err;\n for (let depth = 0; depth < 5 && current instanceof Error; depth++) {\n current = current.cause;\n if (current instanceof PolyesterError) return current;\n }\n return null;\n}\n\n/**\n * Converts any RPC-layer failure into its typed SDK error. Abort errors and\n * caller-cancelled requests pass through unchanged, as do errors that are\n * already typed (e.g. a `NetworkError` from the SDK fetch wrapper).\n */\nexport function toPolyesterError(err: unknown): unknown {\n if (err instanceof PolyesterError) return err;\n if (isAbortError(err)) return err;\n if (err instanceof ConnectError) {\n if (err.code === Code.Canceled) return err;\n const wrapped = findPolyesterErrorInCauseChain(err);\n if (wrapped) return wrapped;\n return connectErrorToPolyesterError(err);\n }\n return err;\n}\n\nasync function* mapStreamErrors<T>(source: AsyncIterable<T>): AsyncIterable<T> {\n try {\n yield* source;\n } catch (err) {\n throw toPolyesterError(err);\n }\n}\n\n/**\n * Interceptor that converts every RPC failure (unary and streaming) into the\n * typed {@link PolyesterError} hierarchy. Installed outermost by\n * `createTransports`, so callers of SDK services always see typed errors.\n */\nexport function createErrorMappingInterceptor(): Interceptor {\n return (next) => async (req) => {\n try {\n const res = await next(req);\n if (res.stream) {\n return { ...res, message: mapStreamErrors(res.message) };\n }\n return res;\n } catch (err) {\n throw toPolyesterError(err);\n }\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"connect-error-mapping.js","names":["OrderErrorDetailSchema"],"sources":["../../src/shared/connect-error-mapping.ts"],"sourcesContent":["import { Code, ConnectError, type Interceptor, type Transport } from \"@connectrpc/connect\";\nimport * as v from \"valibot\";\nimport { AuthErrorCode, AuthErrorDetailSchema } from \"../gen/auth/v1/auth_pb.js\";\nimport {\n ErrorCode as OrderErrorCode,\n ErrorDetailSchema as OrderErrorDetailSchema,\n} from \"../gen/orders/v1/orders_pb.js\";\nimport {\n AlreadyExistsError,\n AuthenticationError,\n InternalServerError,\n isAbortError,\n MfaEnrollmentRequiredError,\n MfaLastFactorRequiredError,\n MfaVerificationError,\n type MfaVerificationFailureReason,\n normalizeErrorMessage,\n PermissionError,\n PolicyInUseError,\n PolicyLockedError,\n PolicyScopeMismatchError,\n PolyesterError,\n type PolyesterErrorOptions,\n PreconditionFailedError,\n RateLimitError,\n ResourceNotFoundError,\n RevisionConflictError,\n ServiceUnavailableError,\n SessionElevationRequiredError,\n StaleQuoteError,\n StepUpRequiredError,\n TimeoutError,\n TransientError,\n ValidationError,\n} from \"./errors.js\";\nimport { RateLimitDetailSchema, type RateLimitDetail } from \"./rate-limit.schemas.js\";\n\nfunction getAuthErrorDetails(err: unknown) {\n return ConnectError.from(err).findDetails(AuthErrorDetailSchema);\n}\n\nfunction hasAuthErrorCode(err: unknown, code: AuthErrorCode): boolean {\n return getAuthErrorDetails(err).some((detail) => detail.code === code);\n}\n\nfunction hasOrderErrorCode(err: unknown, code: OrderErrorCode): boolean {\n return getOrderErrorDetails(err).some((detail) => detail.code === code);\n}\n\nfunction getOrderErrorDetails(err: unknown) {\n return ConnectError.from(err).findDetails(OrderErrorDetailSchema);\n}\n\nfunction getRateLimitDetail(err: unknown): RateLimitDetail | undefined {\n for (const orderDetail of getOrderErrorDetails(err)) {\n if (!orderDetail.rateLimit) continue;\n const result = v.safeParse(RateLimitDetailSchema, orderDetail.rateLimit);\n if (result.success) return result.output;\n }\n return undefined;\n}\n\nfunction safeRetryAfterMs(rateLimit: RateLimitDetail | undefined): number | undefined {\n if (rateLimit?.retryAfterMs === undefined) return undefined;\n const value = BigInt(rateLimit.retryAfterMs);\n return value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : undefined;\n}\n\n/**\n * Returns the error message without the leading \"[code] \" prefix that\n * `ConnectError` prepends, e.g. \"[invalid_argument] Insufficient funds.\"\n * becomes \"Insufficient funds.\".\n */\nexport function getNormalizedConnectMessage(err: unknown): string {\n const ce = ConnectError.from(err);\n const raw = ce.message ?? \"\";\n return normalizeErrorMessage(raw);\n}\n\nexport type MfaErrorKind = \"session-elevation\" | \"enrollment\" | \"step-up\";\n\n/**\n * Classifies an error as one of the MFA flows the backend can demand.\n * Classification is based only on stable structured auth error details.\n */\nexport function detectMfaErrorKind(err: unknown): MfaErrorKind | null {\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_ELEVATION_REQUIRED)) {\n return \"session-elevation\";\n }\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_STEP_UP_REQUIRED)) return \"step-up\";\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_NOT_ENROLLED)) return \"enrollment\";\n return null;\n}\n\nfunction parseRetryAfterMs(ce: ConnectError): number | undefined {\n const value = ce.metadata.get(\"retry-after\");\n if (!value) return undefined;\n const seconds = Number(value);\n if (Number.isFinite(seconds)) return Math.max(0, Math.round(seconds * 1000));\n const date = Date.parse(value);\n if (!Number.isNaN(date)) return Math.max(0, date - Date.now());\n return undefined;\n}\n\nconst MFA_ERROR_CLASSES = {\n \"session-elevation\": SessionElevationRequiredError,\n enrollment: MfaEnrollmentRequiredError,\n \"step-up\": StepUpRequiredError,\n} as const;\n\n/**\n * Maps a `ConnectError` from the Polyester backend onto the typed\n * {@link PolyesterError} tree. The original error is preserved as `cause`.\n */\nexport function connectErrorToPolyesterError(ce: ConnectError): PolyesterError {\n const message = getNormalizedConnectMessage(ce);\n const options: PolyesterErrorOptions = { cause: ce };\n const withFallback = (fallback: string) => message || fallback;\n\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_RESOURCE_NOT_FOUND)) {\n return new ResourceNotFoundError(withFallback(\"Resource not found.\"), options);\n }\n\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_REVISION_CONFLICT)) {\n return new RevisionConflictError(\n withFallback(\"Resource changed since it was last read.\"),\n options,\n );\n }\n\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_POLICY_IN_USE)) {\n return new PolicyInUseError(withFallback(\"Policy is still in use.\"), options);\n }\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_POLICY_LOCKED)) {\n return new PolicyLockedError(withFallback(\"Policy is locked.\"), options);\n }\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_POLICY_SCOPE_MISMATCH)) {\n return new PolicyScopeMismatchError(\n withFallback(\"Policy does not belong to the target account scope.\"),\n options,\n );\n }\n if (hasAuthErrorCode(ce, AuthErrorCode.AUTH_MFA_LAST_FACTOR_REQUIRED)) {\n return new MfaLastFactorRequiredError(\n withFallback(\"At least one active MFA factor must remain enrolled.\"),\n options,\n );\n }\n\n const mfaVerificationReason = getMfaVerificationFailureReason(ce);\n if (mfaVerificationReason) {\n return new MfaVerificationError(\n withFallback(\"MFA verification failed.\"),\n mfaVerificationReason,\n options,\n );\n }\n\n const mfaKind = detectMfaErrorKind(ce);\n if (mfaKind) {\n return new MFA_ERROR_CLASSES[mfaKind](\n withFallback(\"Multi-factor authentication required.\"),\n options,\n );\n }\n\n if (hasOrderErrorCode(ce, OrderErrorCode.STALE_QUOTE)) {\n return new StaleQuoteError(withFallback(\"The submitted market quote is stale.\"), options);\n }\n\n const rateLimit = getRateLimitDetail(ce);\n if (rateLimit || hasOrderErrorCode(ce, OrderErrorCode.RATE_LIMIT_EXCEEDED)) {\n return new RateLimitError(withFallback(\"Rate limit exceeded.\"), {\n ...options,\n rateLimit,\n retryAfterMs: safeRetryAfterMs(rateLimit) ?? parseRetryAfterMs(ce),\n });\n }\n\n switch (ce.code) {\n case Code.InvalidArgument:\n case Code.OutOfRange:\n return new ValidationError(withFallback(\"Invalid request.\"), options);\n case Code.NotFound:\n return new ResourceNotFoundError(withFallback(\"Resource not found.\"), options);\n case Code.AlreadyExists:\n return new AlreadyExistsError(withFallback(\"Resource already exists.\"), options);\n case Code.PermissionDenied:\n return new PermissionError(withFallback(\"Permission denied.\"), options);\n case Code.Unauthenticated:\n return new AuthenticationError(withFallback(\"Authentication required.\"), options);\n case Code.FailedPrecondition:\n return new PreconditionFailedError(withFallback(\"Precondition failed.\"), options);\n case Code.ResourceExhausted:\n return new RateLimitError(withFallback(\"Rate limit exceeded.\"), {\n ...options,\n retryAfterMs: parseRetryAfterMs(ce),\n });\n case Code.DeadlineExceeded:\n return new TimeoutError(withFallback(\"Request timed out.\"), options);\n case Code.Unavailable:\n return new ServiceUnavailableError(withFallback(\"Service unavailable.\"), options);\n case Code.Aborted:\n return new TransientError(withFallback(\"Operation aborted by the backend.\"), options);\n default:\n // Gateways sometimes surface outages as Unknown with this stock phrase.\n if (/service temporarily unavailable/i.test(message)) {\n return new ServiceUnavailableError(withFallback(\"Service unavailable.\"), options);\n }\n return new InternalServerError(withFallback(\"Internal server error.\"), options);\n }\n}\n\nfunction getMfaVerificationFailureReason(err: unknown): MfaVerificationFailureReason | null {\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_CHALLENGE_INVALID)) {\n return \"challenge-invalid\";\n }\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_CHALLENGE_LOCKED)) {\n return \"challenge-locked\";\n }\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_OTP_INVALID)) return \"otp-invalid\";\n if (hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_RECOVERY_INVALID)) {\n return \"recovery-code-invalid\";\n }\n if (\n hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_PASSKEY_CREDENTIAL_INVALID) ||\n hasAuthErrorCode(err, AuthErrorCode.AUTH_MFA_PASSKEY_VERIFY_FAILED)\n ) {\n return \"passkey-invalid\";\n }\n\n return null;\n}\n\nfunction findPolyesterErrorInCauseChain(err: unknown): PolyesterError | null {\n let current: unknown = err;\n for (let depth = 0; depth < 5 && current instanceof Error; depth++) {\n current = current.cause;\n if (current instanceof PolyesterError) return current;\n }\n return null;\n}\n\n/**\n * Converts any RPC-layer failure into its typed SDK error. Abort errors and\n * caller-cancelled requests pass through unchanged, as do errors that are\n * already typed (e.g. a `NetworkError` from the SDK fetch wrapper).\n */\nexport function toPolyesterError(err: unknown): unknown {\n if (err instanceof PolyesterError) return err;\n if (isAbortError(err)) return err;\n if (err instanceof ConnectError) {\n if (err.code === Code.Canceled) return err;\n const wrapped = findPolyesterErrorInCauseChain(err);\n if (wrapped) return wrapped;\n return connectErrorToPolyesterError(err);\n }\n return err;\n}\n\nasync function* mapStreamErrors<T>(source: AsyncIterable<T>): AsyncIterable<T> {\n try {\n yield* source;\n } catch (err) {\n throw toPolyesterError(err);\n }\n}\n\n/**\n * Interceptor that converts every RPC failure (unary and streaming) into the\n * typed {@link PolyesterError} hierarchy. Installed outermost by\n * `createTransports`, so callers of SDK services always see typed errors.\n */\nexport function createErrorMappingInterceptor(): Interceptor {\n return (next) => async (req) => {\n try {\n const res = await next(req);\n if (res.stream) {\n return { ...res, message: mapStreamErrors(res.message) };\n }\n return res;\n } catch (err) {\n throw toPolyesterError(err);\n }\n };\n}\n\n/**\n * Wraps a Connect transport so errors are translated after Connect's call\n * runner has applied its own error normalization.\n */\nexport function createErrorMappingTransport(transport: Transport): Transport {\n return {\n async unary(method, signal, timeoutMs, header, input, contextValues) {\n try {\n return await transport.unary(\n method,\n signal,\n timeoutMs,\n header,\n input,\n contextValues,\n );\n } catch (error) {\n throw toPolyesterError(error);\n }\n },\n async stream(method, signal, timeoutMs, header, input, contextValues) {\n try {\n const response = await transport.stream(\n method,\n signal,\n timeoutMs,\n header,\n input,\n contextValues,\n );\n return { ...response, message: mapStreamErrors(response.message) };\n } catch (error) {\n throw toPolyesterError(error);\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConfigurationError, NetworkError, isAbortError } from "./errors.js";
|
|
2
|
-
import {
|
|
2
|
+
import { createErrorMappingTransport } from "./connect-error-mapping.js";
|
|
3
3
|
import { createConnectTransport } from "@connectrpc/connect-web";
|
|
4
4
|
import { toBinary, toJsonString } from "@bufbuild/protobuf";
|
|
5
5
|
import { signAsync } from "@noble/ed25519";
|
|
@@ -28,25 +28,20 @@ function makeFetch() {
|
|
|
28
28
|
function createTransports(config) {
|
|
29
29
|
const { apiUrl, interceptors = [], auth, wireFormat = "binary" } = config;
|
|
30
30
|
const useBinaryFormat = wireFormat === "binary";
|
|
31
|
-
const
|
|
32
|
-
const publicApi = createConnectTransport({
|
|
31
|
+
const publicApi = createErrorMappingTransport(createConnectTransport({
|
|
33
32
|
baseUrl: apiUrl,
|
|
34
33
|
useBinaryFormat,
|
|
35
|
-
interceptors
|
|
34
|
+
interceptors,
|
|
36
35
|
fetch: makeFetch()
|
|
37
|
-
});
|
|
38
|
-
const authInterceptors = auth ? [
|
|
39
|
-
errorMapping,
|
|
40
|
-
createAuthInterceptor(auth, { wireFormat }),
|
|
41
|
-
...interceptors
|
|
42
|
-
] : [errorMapping, ...interceptors];
|
|
36
|
+
}));
|
|
37
|
+
const authInterceptors = auth ? [createAuthInterceptor(auth, { wireFormat }), ...interceptors] : interceptors;
|
|
43
38
|
return {
|
|
44
|
-
authApi: createConnectTransport({
|
|
39
|
+
authApi: createErrorMappingTransport(createConnectTransport({
|
|
45
40
|
baseUrl: apiUrl,
|
|
46
41
|
useBinaryFormat,
|
|
47
42
|
interceptors: authInterceptors,
|
|
48
43
|
fetch: makeFetch()
|
|
49
|
-
}),
|
|
44
|
+
})),
|
|
50
45
|
publicApi
|
|
51
46
|
};
|
|
52
47
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transports.js","names":[],"sources":["../../src/shared/transports.ts"],"sourcesContent":["import { createConnectTransport } from \"@connectrpc/connect-web\";\nimport type { Transport, Interceptor } from \"@connectrpc/connect\";\nimport { toBinary, toJsonString } from \"@bufbuild/protobuf\";\nimport { signAsync } from \"@noble/ed25519\";\nimport { createErrorMappingInterceptor } from \"./connect-error-mapping.js\";\nimport { ConfigurationError, isAbortError, NetworkError } from \"./errors.js\";\n\nexport { isAbortError };\n\nexport type ConnectWireFormat = \"binary\" | \"json\";\n\nexport const POLYESTER_MOCK_HEADER = \"x-polyester-mock\";\n\nexport interface TransportConfig {\n apiUrl: string;\n interceptors?: Interceptor[];\n auth?: JwtAuthProvider | ApiKeyEd25519AuthProvider;\n /**\n * Connect wire format. Defaults to binary for production performance.\n * Use `json` for the API Playground visualization.\n */\n wireFormat?: ConnectWireFormat;\n}\n\nexport interface Transports {\n authApi: Transport;\n publicApi: Transport;\n}\n\n/**\n * Generic JWT auth for HTTP/Connect endpoints that follow the Bearer token contract.\n */\nexport interface JwtAuthProvider {\n kind: \"jwt\";\n /** Typically wraps the configured browser auth token storage. */\n getToken: () => string | null | Promise<string | null>;\n}\n\n/**\n * Generic Ed25519 API key auth for HTTP/Connect endpoints that follow the\n * X-API-KEY-ID / X-API-TIMESTAMP / X-API-SIGNATURE contract.\n */\nexport interface ApiKeyEd25519AuthProvider {\n kind: \"api-key-ed25519\";\n getKeyId: () => string | null | Promise<string | null>;\n /** Ed25519 secret key bytes (not hex) for signing. */\n getSecretKey: () => Uint8Array | null | Promise<Uint8Array | null>;\n}\n\nexport interface ApiKeyEd25519SigningRequest {\n url: string | URL;\n method: string;\n body?: Uint8Array;\n timestamp?: string;\n}\n\n/**\n * Returns the fetch implementation used by SDK transports.\n */\nexport function makeFetch(): typeof fetch {\n const wrappedFetch = Object.assign(\n async (input: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => {\n // Normalize headers into a mutable Headers object\n const headers = new Headers(init?.headers);\n\n try {\n const res = await fetch(input, {\n ...init,\n headers,\n redirect: \"manual\",\n });\n\n return res;\n } catch (err) {\n if (isAbortError(err)) throw err;\n throw new NetworkError(\"Transport request failed\", { cause: err });\n }\n },\n fetch,\n );\n\n return wrappedFetch;\n}\n\n/**\n * Creates Connect transports for SDK service clients.\n */\nexport function createTransports(config: TransportConfig): Transports {\n const { apiUrl, interceptors = [], auth, wireFormat = \"binary\" } = config;\n const useBinaryFormat = wireFormat === \"binary\";\n // Outermost so every RPC failure surfaces as a typed PolyesterError.\n const errorMapping = createErrorMappingInterceptor();\n\n const publicApi = createConnectTransport({\n baseUrl: apiUrl,\n useBinaryFormat,\n interceptors: [errorMapping, ...interceptors],\n fetch: makeFetch(),\n });\n\n const authInterceptors = auth\n ? [errorMapping, createAuthInterceptor(auth, { wireFormat }), ...interceptors]\n : [errorMapping, ...interceptors];\n const authApi = createConnectTransport({\n baseUrl: apiUrl,\n useBinaryFormat,\n interceptors: authInterceptors,\n fetch: makeFetch(),\n });\n\n return { authApi, publicApi };\n}\n\n/**\n * Creates an interceptor that enables mock transport behavior.\n */\nexport function createMockInterceptor(getEnabled: () => boolean): Interceptor {\n return (next) => async (req) => {\n if (getEnabled()) req.header.set(POLYESTER_MOCK_HEADER, \"true\");\n return next(req);\n };\n}\n\nasync function sha256Hex(bytes: Uint8Array): Promise<string> {\n if (typeof crypto === \"undefined\" || !crypto.subtle) {\n throw new ConfigurationError(\"SHA-256 not available in this environment\");\n }\n const hash = await crypto.subtle.digest(\"SHA-256\", bytes.slice());\n return Array.from(new Uint8Array(hash), (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nfunction canonicalQueryString(params: URLSearchParams): string {\n const pairs: string[] = [];\n for (const [k, v] of params.entries()) {\n pairs.push(`${encodeURIComponent(k)}=${encodeURIComponent(v)}`);\n }\n pairs.sort();\n return pairs.join(\"&\");\n}\n\n/**\n * Creates API-key authentication headers for endpoints using the Polyester Ed25519 signing contract.\n */\nexport async function createApiKeyEd25519AuthHeaders(\n auth: ApiKeyEd25519AuthProvider,\n request: ApiKeyEd25519SigningRequest,\n): Promise<Record<string, string>> {\n const [keyId, secretKey] = await Promise.all([auth.getKeyId(), auth.getSecretKey()]);\n if (!keyId || !secretKey) throw new ConfigurationError(\"Missing API key ID or secret key\");\n\n const urlObj = new URL(request.url);\n const timestamp = request.timestamp ?? String(Date.now());\n const bodyHash = await sha256Hex(request.body ?? new Uint8Array(0));\n const canonicalQuery = canonicalQueryString(urlObj.searchParams);\n const canonical = `${timestamp}\\n${request.method}\\n${urlObj.pathname}\\n${canonicalQuery}\\n${bodyHash}`;\n const msgBytes = new TextEncoder().encode(canonical);\n const sig = await signAsync(msgBytes, secretKey);\n const signatureHex = Array.from(sig, (b: number) => b.toString(16).padStart(2, \"0\")).join(\"\");\n\n return {\n \"X-API-KEY-ID\": keyId,\n \"X-API-TIMESTAMP\": timestamp,\n \"X-API-SIGNATURE\": signatureHex,\n };\n}\n\n/**\n * Creates an interceptor that attaches SDK authentication headers.\n */\nexport function createAuthInterceptor(\n auth: JwtAuthProvider | ApiKeyEd25519AuthProvider,\n options?: { wireFormat?: ConnectWireFormat },\n): Interceptor {\n return (next) => async (req) => {\n const wireFormat = options?.wireFormat ?? \"binary\";\n if (auth.kind === \"jwt\") {\n const token = await auth.getToken();\n if (token) {\n req.header.set(\"Authorization\", `Bearer ${token}`);\n }\n } else if (auth.kind === \"api-key-ed25519\") {\n let bodyBytes: Uint8Array;\n if (!req.stream) {\n // unary request - serialize the message using the method's input schema\n const inputSchema = req.method.input;\n bodyBytes =\n wireFormat === \"json\"\n ? new TextEncoder().encode(toJsonString(inputSchema, req.message))\n : toBinary(inputSchema, req.message);\n } else {\n // stream request - empty body for signing (streams don't have a single body)\n bodyBytes = new Uint8Array(0);\n }\n\n const headers = await createApiKeyEd25519AuthHeaders(auth, {\n url: req.url,\n method: req.requestMethod,\n body: bodyBytes,\n });\n for (const [key, value] of Object.entries(headers)) {\n req.header.set(key, value);\n }\n }\n return next(req);\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transports.js","names":[],"sources":["../../src/shared/transports.ts"],"sourcesContent":["import { createConnectTransport } from \"@connectrpc/connect-web\";\nimport type { Transport, Interceptor } from \"@connectrpc/connect\";\nimport { toBinary, toJsonString } from \"@bufbuild/protobuf\";\nimport { signAsync } from \"@noble/ed25519\";\nimport { createErrorMappingTransport } from \"./connect-error-mapping.js\";\nimport { ConfigurationError, isAbortError, NetworkError } from \"./errors.js\";\n\nexport { isAbortError };\n\nexport type ConnectWireFormat = \"binary\" | \"json\";\n\nexport const POLYESTER_MOCK_HEADER = \"x-polyester-mock\";\n\nexport interface TransportConfig {\n apiUrl: string;\n interceptors?: Interceptor[];\n auth?: JwtAuthProvider | ApiKeyEd25519AuthProvider;\n /**\n * Connect wire format. Defaults to binary for production performance.\n * Use `json` for the API Playground visualization.\n */\n wireFormat?: ConnectWireFormat;\n}\n\nexport interface Transports {\n authApi: Transport;\n publicApi: Transport;\n}\n\n/**\n * Generic JWT auth for HTTP/Connect endpoints that follow the Bearer token contract.\n */\nexport interface JwtAuthProvider {\n kind: \"jwt\";\n /** Typically wraps the configured browser auth token storage. */\n getToken: () => string | null | Promise<string | null>;\n}\n\n/**\n * Generic Ed25519 API key auth for HTTP/Connect endpoints that follow the\n * X-API-KEY-ID / X-API-TIMESTAMP / X-API-SIGNATURE contract.\n */\nexport interface ApiKeyEd25519AuthProvider {\n kind: \"api-key-ed25519\";\n getKeyId: () => string | null | Promise<string | null>;\n /** Ed25519 secret key bytes (not hex) for signing. */\n getSecretKey: () => Uint8Array | null | Promise<Uint8Array | null>;\n}\n\nexport interface ApiKeyEd25519SigningRequest {\n url: string | URL;\n method: string;\n body?: Uint8Array;\n timestamp?: string;\n}\n\n/**\n * Returns the fetch implementation used by SDK transports.\n */\nexport function makeFetch(): typeof fetch {\n const wrappedFetch = Object.assign(\n async (input: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => {\n // Normalize headers into a mutable Headers object\n const headers = new Headers(init?.headers);\n\n try {\n const res = await fetch(input, {\n ...init,\n headers,\n redirect: \"manual\",\n });\n\n return res;\n } catch (err) {\n if (isAbortError(err)) throw err;\n throw new NetworkError(\"Transport request failed\", { cause: err });\n }\n },\n fetch,\n );\n\n return wrappedFetch;\n}\n\n/**\n * Creates Connect transports for SDK service clients.\n */\nexport function createTransports(config: TransportConfig): Transports {\n const { apiUrl, interceptors = [], auth, wireFormat = \"binary\" } = config;\n const useBinaryFormat = wireFormat === \"binary\";\n const publicApi = createErrorMappingTransport(\n createConnectTransport({\n baseUrl: apiUrl,\n useBinaryFormat,\n interceptors,\n fetch: makeFetch(),\n }),\n );\n\n const authInterceptors = auth\n ? [createAuthInterceptor(auth, { wireFormat }), ...interceptors]\n : interceptors;\n const authApi = createErrorMappingTransport(\n createConnectTransport({\n baseUrl: apiUrl,\n useBinaryFormat,\n interceptors: authInterceptors,\n fetch: makeFetch(),\n }),\n );\n\n return { authApi, publicApi };\n}\n\n/**\n * Creates an interceptor that enables mock transport behavior.\n */\nexport function createMockInterceptor(getEnabled: () => boolean): Interceptor {\n return (next) => async (req) => {\n if (getEnabled()) req.header.set(POLYESTER_MOCK_HEADER, \"true\");\n return next(req);\n };\n}\n\nasync function sha256Hex(bytes: Uint8Array): Promise<string> {\n if (typeof crypto === \"undefined\" || !crypto.subtle) {\n throw new ConfigurationError(\"SHA-256 not available in this environment\");\n }\n const hash = await crypto.subtle.digest(\"SHA-256\", bytes.slice());\n return Array.from(new Uint8Array(hash), (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nfunction canonicalQueryString(params: URLSearchParams): string {\n const pairs: string[] = [];\n for (const [k, v] of params.entries()) {\n pairs.push(`${encodeURIComponent(k)}=${encodeURIComponent(v)}`);\n }\n pairs.sort();\n return pairs.join(\"&\");\n}\n\n/**\n * Creates API-key authentication headers for endpoints using the Polyester Ed25519 signing contract.\n */\nexport async function createApiKeyEd25519AuthHeaders(\n auth: ApiKeyEd25519AuthProvider,\n request: ApiKeyEd25519SigningRequest,\n): Promise<Record<string, string>> {\n const [keyId, secretKey] = await Promise.all([auth.getKeyId(), auth.getSecretKey()]);\n if (!keyId || !secretKey) throw new ConfigurationError(\"Missing API key ID or secret key\");\n\n const urlObj = new URL(request.url);\n const timestamp = request.timestamp ?? String(Date.now());\n const bodyHash = await sha256Hex(request.body ?? new Uint8Array(0));\n const canonicalQuery = canonicalQueryString(urlObj.searchParams);\n const canonical = `${timestamp}\\n${request.method}\\n${urlObj.pathname}\\n${canonicalQuery}\\n${bodyHash}`;\n const msgBytes = new TextEncoder().encode(canonical);\n const sig = await signAsync(msgBytes, secretKey);\n const signatureHex = Array.from(sig, (b: number) => b.toString(16).padStart(2, \"0\")).join(\"\");\n\n return {\n \"X-API-KEY-ID\": keyId,\n \"X-API-TIMESTAMP\": timestamp,\n \"X-API-SIGNATURE\": signatureHex,\n };\n}\n\n/**\n * Creates an interceptor that attaches SDK authentication headers.\n */\nexport function createAuthInterceptor(\n auth: JwtAuthProvider | ApiKeyEd25519AuthProvider,\n options?: { wireFormat?: ConnectWireFormat },\n): Interceptor {\n return (next) => async (req) => {\n const wireFormat = options?.wireFormat ?? \"binary\";\n if (auth.kind === \"jwt\") {\n const token = await auth.getToken();\n if (token) {\n req.header.set(\"Authorization\", `Bearer ${token}`);\n }\n } else if (auth.kind === \"api-key-ed25519\") {\n let bodyBytes: Uint8Array;\n if (!req.stream) {\n // unary request - serialize the message using the method's input schema\n const inputSchema = req.method.input;\n bodyBytes =\n wireFormat === \"json\"\n ? new TextEncoder().encode(toJsonString(inputSchema, req.message))\n : toBinary(inputSchema, req.message);\n } else {\n // stream request - empty body for signing (streams don't have a single body)\n bodyBytes = new Uint8Array(0);\n }\n\n const headers = await createApiKeyEd25519AuthHeaders(auth, {\n url: req.url,\n method: req.requestMethod,\n body: bodyBytes,\n });\n for (const [key, value] of Object.entries(headers)) {\n req.header.set(key, value);\n }\n }\n return next(req);\n };\n}\n"],"mappings":"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"}
|
package/dist/shared/types.d.ts
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import { SdkSubscriptionErrorContext } from "./subscription-errors.js";
|
|
2
2
|
//#region src/shared/types.d.ts
|
|
3
3
|
interface BaseSubscribeInput<T> {
|
|
4
|
+
/**
|
|
5
|
+
* Called after the channel subscription is confirmed. The unsubscribe function
|
|
6
|
+
* returned by subscribe only starts the connection; wait for the first onOpen
|
|
7
|
+
* call before issuing writes whose events must be observed. Called again after
|
|
8
|
+
* a successful resubscription.
|
|
9
|
+
*/
|
|
4
10
|
onOpen?: () => void;
|
|
11
|
+
/** Called when an active channel subscription closes. */
|
|
5
12
|
onClose?: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Called when the subscription or an event handler reports an error. When omitted,
|
|
15
|
+
* a synchronously detected missing-authentication failure throws instead.
|
|
16
|
+
*/
|
|
6
17
|
onError?: (ctx: SdkSubscriptionErrorContext) => void;
|
|
18
|
+
/** Called for each event received while the channel subscription is active. */
|
|
7
19
|
onEvent: (c: T) => void;
|
|
8
20
|
}
|
|
9
21
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/shared/types.ts"],"mappings":";;UAEiB,mBAAmB
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/shared/types.ts"],"mappings":";;UAEiB,mBAAmB;;;;;;;EAOhC;;EAEA;;;;;EAKA,WAAW,KAAK;;EAEhB,UAAU,GAAG"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ValidationError } from "./errors.js";
|
|
2
|
+
import * as v from "valibot";
|
|
3
|
+
//#region src/shared/validation.ts
|
|
4
|
+
/**
|
|
5
|
+
* Parses a value with Valibot and translates schema failures into the SDK's
|
|
6
|
+
* public error hierarchy.
|
|
7
|
+
*/
|
|
8
|
+
function parse(schema, input, config) {
|
|
9
|
+
try {
|
|
10
|
+
return v.parse(schema, input, config);
|
|
11
|
+
} catch (error) {
|
|
12
|
+
if (v.isValiError(error)) throw new ValidationError(error.message, { cause: error });
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { parse };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","names":[],"sources":["../../src/shared/validation.ts"],"sourcesContent":["import * as v from \"valibot\";\nimport { ValidationError } from \"./errors.js\";\n\n/**\n * Parses a value with Valibot and translates schema failures into the SDK's\n * public error hierarchy.\n */\nexport function parse<const TSchema extends v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>>(\n schema: TSchema,\n input: unknown,\n config?: v.Config<v.InferIssue<TSchema>>,\n): v.InferOutput<TSchema> {\n try {\n return v.parse(schema, input, config);\n } catch (error) {\n if (v.isValiError(error)) {\n throw new ValidationError(error.message, { cause: error });\n }\n throw error;\n }\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,MACZ,QACA,OACA,QACsB;CACtB,IAAI;EACA,OAAO,EAAE,MAAM,QAAQ,OAAO,MAAM;CACxC,SAAS,OAAO;EACZ,IAAI,EAAE,YAAY,KAAK,GACnB,MAAM,IAAI,gBAAgB,MAAM,SAAS,EAAE,OAAO,MAAM,CAAC;EAE7D,MAAM;CACV;AACJ"}
|
package/dist/utils/cookies.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
//#region src/utils/cookies.d.ts
|
|
2
|
-
type
|
|
3
|
-
|
|
4
|
-
}
|
|
2
|
+
type CookieValue = string | {
|
|
3
|
+
readonly value: string;
|
|
4
|
+
};
|
|
5
|
+
type CookieStoreLike = {
|
|
6
|
+
get(name: string): CookieValue | undefined;
|
|
7
|
+
};
|
|
8
|
+
/** A supported server-side cookie source. */
|
|
9
|
+
type CookieGetter = Record<string, string> | CookieStoreLike | Request;
|
|
5
10
|
//#endregion
|
|
6
11
|
export { CookieGetter };
|
|
7
12
|
//# sourceMappingURL=cookies.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookies.d.ts","names":[],"sources":["../../src/utils/cookies.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"cookies.d.ts","names":[],"sources":["../../src/utils/cookies.ts"],"mappings":";KA6DK;WAAkC;;KAClC;EAAoB,IAAI,eAAe;;;KAGhC,eAAe,yBAAyB,kBAAkB"}
|
package/dist/utils/cookies.js
CHANGED
|
@@ -42,6 +42,9 @@ function deleteCookie(name, options) {
|
|
|
42
42
|
expires: /* @__PURE__ */ new Date("Thu, 01 Jan 1970 00:00:00 GMT")
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
+
function isCookieStore(cookies) {
|
|
46
|
+
return typeof cookies.get === "function";
|
|
47
|
+
}
|
|
45
48
|
/**
|
|
46
49
|
* Parses cookies from a Request header.
|
|
47
50
|
*/
|
|
@@ -55,7 +58,10 @@ function parseCookiesFromRequest(request) {
|
|
|
55
58
|
*/
|
|
56
59
|
function getCookieValue(cookies, name) {
|
|
57
60
|
if (cookies instanceof Request) return parseCookiesFromRequest(cookies)[name];
|
|
58
|
-
if (
|
|
61
|
+
if (isCookieStore(cookies)) {
|
|
62
|
+
const cookie = cookies.get(name);
|
|
63
|
+
return typeof cookie === "string" ? cookie : cookie?.value;
|
|
64
|
+
}
|
|
59
65
|
return cookies[name];
|
|
60
66
|
}
|
|
61
67
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookies.js","names":["serializeCookie","parseCookie","#name"],"sources":["../../src/utils/cookies.ts"],"sourcesContent":["import {\n type Cookies,\n type CookieSerializeOptions,\n parseCookie,\n serializeCookie,\n} from \"./cookie-es/index.js\";\nimport { isLocalNetworkHost } from \"./is-dev.js\";\n\n/**\n * Whether auth cookies should carry the `Secure` attribute.\n *\n * On https pages: always Secure. On plaintext pages, browsers silently DROP\n * Secure cookies (localhost excepted), so dev against a LAN IP — e.g. phone\n * testing http://192.168.x.x — logged users out instantly because the freshly\n * written session cookies never persisted. The downgrade is therefore allowed\n * ONLY on local/private-network hosts; on a public hostname served over http\n * (a misconfigured production deployment) cookies stay Secure so auth fails\n * closed instead of shipping session cookies over plaintext.\n */\nexport function shouldSecureCookies(): boolean {\n if (typeof window === \"undefined\") return true;\n if (window.location.protocol === \"https:\") return true;\n return !isLocalNetworkHost(window.location.hostname);\n}\n\ninterface SetCookieParams {\n name: string;\n value: string;\n options: CookieSerializeOptions;\n}\n\n/**\n * Writes a browser cookie.\n */\nexport function setCookie({ name, value, options }: SetCookieParams): void {\n if (typeof document === \"undefined\") return;\n\n document.cookie = serializeCookie(name, value, options);\n}\n\n/**\n * Reads a browser cookie by name.\n */\nexport function getCookie(name: string): string | undefined {\n if (typeof document === \"undefined\") return;\n\n return parseCookie(document.cookie)[name];\n}\n\n/**\n * Deletes a browser cookie by name.\n */\nexport function deleteCookie(name: string, options?: { path?: string }): void {\n if (typeof document === \"undefined\") return;\n\n document.cookie = serializeCookie(name, \"\", {\n path: options?.path ?? \"/\",\n expires: new Date(\"Thu, 01 Jan 1970 00:00:00 GMT\"),\n });\n}\n\
|
|
1
|
+
{"version":3,"file":"cookies.js","names":["serializeCookie","parseCookie","#name"],"sources":["../../src/utils/cookies.ts"],"sourcesContent":["import {\n type Cookies,\n type CookieSerializeOptions,\n parseCookie,\n serializeCookie,\n} from \"./cookie-es/index.js\";\nimport { isLocalNetworkHost } from \"./is-dev.js\";\n\n/**\n * Whether auth cookies should carry the `Secure` attribute.\n *\n * On https pages: always Secure. On plaintext pages, browsers silently DROP\n * Secure cookies (localhost excepted), so dev against a LAN IP — e.g. phone\n * testing http://192.168.x.x — logged users out instantly because the freshly\n * written session cookies never persisted. The downgrade is therefore allowed\n * ONLY on local/private-network hosts; on a public hostname served over http\n * (a misconfigured production deployment) cookies stay Secure so auth fails\n * closed instead of shipping session cookies over plaintext.\n */\nexport function shouldSecureCookies(): boolean {\n if (typeof window === \"undefined\") return true;\n if (window.location.protocol === \"https:\") return true;\n return !isLocalNetworkHost(window.location.hostname);\n}\n\ninterface SetCookieParams {\n name: string;\n value: string;\n options: CookieSerializeOptions;\n}\n\n/**\n * Writes a browser cookie.\n */\nexport function setCookie({ name, value, options }: SetCookieParams): void {\n if (typeof document === \"undefined\") return;\n\n document.cookie = serializeCookie(name, value, options);\n}\n\n/**\n * Reads a browser cookie by name.\n */\nexport function getCookie(name: string): string | undefined {\n if (typeof document === \"undefined\") return;\n\n return parseCookie(document.cookie)[name];\n}\n\n/**\n * Deletes a browser cookie by name.\n */\nexport function deleteCookie(name: string, options?: { path?: string }): void {\n if (typeof document === \"undefined\") return;\n\n document.cookie = serializeCookie(name, \"\", {\n path: options?.path ?? \"/\",\n expires: new Date(\"Thu, 01 Jan 1970 00:00:00 GMT\"),\n });\n}\n\ntype CookieValue = string | { readonly value: string };\ntype CookieStoreLike = { get(name: string): CookieValue | undefined };\n\n/** A supported server-side cookie source. */\nexport type CookieGetter = Record<string, string> | CookieStoreLike | Request;\n\nfunction isCookieStore(\n cookies: Record<string, string> | CookieStoreLike,\n): cookies is CookieStoreLike {\n return typeof cookies.get === \"function\";\n}\n\n/**\n * Parses cookies from a Request header.\n */\nexport function parseCookiesFromRequest(request: Request): Cookies {\n const cookieHeader = request.headers.get(\"cookie\");\n if (!cookieHeader) return {};\n\n return parseCookie(cookieHeader);\n}\n\n/**\n * Reads a cookie value from either a cookie map or cookie getter.\n */\nexport function getCookieValue(cookies: CookieGetter, name: string): string | undefined {\n if (cookies instanceof Request) {\n const parsed = parseCookiesFromRequest(cookies);\n return parsed[name];\n }\n if (isCookieStore(cookies)) {\n const cookie = cookies.get(name);\n return typeof cookie === \"string\" ? cookie : cookie?.value;\n }\n return cookies[name];\n}\n\ninterface CookieManagerOptions {\n /**\n * The name of the cookie to manage.\n */\n name: string;\n}\n\n/**\n * A generic class for managing cookies on the client side.\n * Provides a consistent interface for getting, setting, and deleting cookies.\n *\n * @example\n * ```ts\n * const cookieManager = new CookieManager({ name: \"my-cookie\" });\n * cookieManager.get();\n * cookieManager.set(\"my-value\");\n * cookieManager.clear();\n * ```\n */\nexport class CookieManager {\n #name: string;\n constructor(opts: CookieManagerOptions) {\n this.#name = opts.name;\n }\n /**\n * Reads the managed cookie value.\n */\n get(): string | null {\n const token = getCookie(this.#name);\n return token ?? null;\n }\n\n /**\n * Writes the managed cookie value.\n */\n set(\n token: string,\n options?: {\n path?: string;\n secure?: boolean;\n sameSite?: \"lax\" | \"strict\" | \"none\";\n maxAge?: number;\n expires?: Date;\n },\n ): void {\n setCookie({\n name: this.#name,\n value: token,\n options: {\n path: options?.path ?? \"/\",\n sameSite: options?.sameSite ?? \"lax\",\n secure: options?.secure ?? shouldSecureCookies(),\n maxAge: options?.maxAge,\n expires: options?.expires,\n },\n });\n }\n\n /**\n * Clears the managed cookie value.\n */\n clear(options?: { path?: string }): void {\n deleteCookie(this.#name, options);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmBA,SAAgB,sBAA+B;CAC3C,IAAI,OAAO,WAAW,aAAa,OAAO;CAC1C,IAAI,OAAO,SAAS,aAAa,UAAU,OAAO;CAClD,OAAO,CAAC,mBAAmB,OAAO,SAAS,QAAQ;AACvD;;;;AAWA,SAAgB,UAAU,EAAE,MAAM,OAAO,WAAkC;CACvE,IAAI,OAAO,aAAa,aAAa;CAErC,SAAS,SAASA,UAAgB,MAAM,OAAO,OAAO;AAC1D;;;;AAKA,SAAgB,UAAU,MAAkC;CACxD,IAAI,OAAO,aAAa,aAAa;CAErC,OAAOC,MAAY,SAAS,MAAM,CAAC,CAAC;AACxC;;;;AAKA,SAAgB,aAAa,MAAc,SAAmC;CAC1E,IAAI,OAAO,aAAa,aAAa;CAErC,SAAS,SAASD,UAAgB,MAAM,IAAI;EACxC,MAAM,SAAS,QAAQ;EACvB,yBAAS,IAAI,KAAK,+BAA+B;CACrD,CAAC;AACL;AAQA,SAAS,cACL,SAC0B;CAC1B,OAAO,OAAO,QAAQ,QAAQ;AAClC;;;;AAKA,SAAgB,wBAAwB,SAA2B;CAC/D,MAAM,eAAe,QAAQ,QAAQ,IAAI,QAAQ;CACjD,IAAI,CAAC,cAAc,OAAO,CAAC;CAE3B,OAAOC,MAAY,YAAY;AACnC;;;;AAKA,SAAgB,eAAe,SAAuB,MAAkC;CACpF,IAAI,mBAAmB,SAEnB,OADe,wBAAwB,OAC3B,CAAC,CAAC;CAElB,IAAI,cAAc,OAAO,GAAG;EACxB,MAAM,SAAS,QAAQ,IAAI,IAAI;EAC/B,OAAO,OAAO,WAAW,WAAW,SAAS,QAAQ;CACzD;CACA,OAAO,QAAQ;AACnB;;;;;;;;;;;;;AAqBA,IAAa,gBAAb,MAA2B;CACvB;CACA,YAAY,MAA4B;EACpC,KAAKC,QAAQ,KAAK;CACtB;;;;CAIA,MAAqB;EAEjB,OADc,UAAU,KAAKA,KAClB,KAAK;CACpB;;;;CAKA,IACI,OACA,SAOI;EACJ,UAAU;GACN,MAAM,KAAKA;GACX,OAAO;GACP,SAAS;IACL,MAAM,SAAS,QAAQ;IACvB,UAAU,SAAS,YAAY;IAC/B,QAAQ,SAAS,UAAU,oBAAoB;IAC/C,QAAQ,SAAS;IACjB,SAAS,SAAS;GACtB;EACJ,CAAC;CACL;;;;CAKA,MAAM,SAAmC;EACrC,aAAa,KAAKA,OAAO,OAAO;CACpC;AACJ"}
|
|
@@ -14,7 +14,7 @@ declare class EventEmitter<TEvents extends { [K in keyof TEvents]: unknown; }> {
|
|
|
14
14
|
*/
|
|
15
15
|
once<K extends keyof TEvents>(event: K, callback: EventCallback<TEvents[K]>): () => void;
|
|
16
16
|
/**
|
|
17
|
-
* Emits an event to all registered listeners.
|
|
17
|
+
* Emits an event to all registered listeners, isolating errors thrown synchronously by each listener.
|
|
18
18
|
*/
|
|
19
19
|
emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void;
|
|
20
20
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-emitter.d.ts","names":[],"sources":["../../src/utils/event-emitter.ts"],"mappings":";KAAK,cAAc,gBAAgB,MAAM;;;;cAK5B,aAAa,mBAAmB,WAAW;;;;;EAMpD,GAAG,gBAAgB,SAAS,OAAO,GAAG,UAAU,cAAc,QAAQ;;;;EActE,KAAK,gBAAgB,SAAS,OAAO,GAAG,UAAU,cAAc,QAAQ;;;;EAWxE,KAAK,gBAAgB,SAAS,OAAO,GAAG,MAAM,QAAQ;;;;
|
|
1
|
+
{"version":3,"file":"event-emitter.d.ts","names":[],"sources":["../../src/utils/event-emitter.ts"],"mappings":";KAAK,cAAc,gBAAgB,MAAM;;;;cAK5B,aAAa,mBAAmB,WAAW;;;;;EAMpD,GAAG,gBAAgB,SAAS,OAAO,GAAG,UAAU,cAAc,QAAQ;;;;EActE,KAAK,gBAAgB,SAAS,OAAO,GAAG,UAAU,cAAc,QAAQ;;;;EAWxE,KAAK,gBAAgB,SAAS,OAAO,GAAG,MAAM,QAAQ;;;;EAgBtD,IAAI,gBAAgB,SAAS,OAAO,GAAG,WAAW,cAAc,QAAQ;;;;EAWxE"}
|
|
@@ -25,11 +25,13 @@ var EventEmitter = class {
|
|
|
25
25
|
return unsubscribe;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* Emits an event to all registered listeners.
|
|
28
|
+
* Emits an event to all registered listeners, isolating errors thrown synchronously by each listener.
|
|
29
29
|
*/
|
|
30
30
|
emit(event, data) {
|
|
31
31
|
const callbacks = this.#listeners.get(event);
|
|
32
|
-
if (callbacks) for (const callback of callbacks)
|
|
32
|
+
if (callbacks) for (const callback of callbacks) try {
|
|
33
|
+
callback(data);
|
|
34
|
+
} catch {}
|
|
33
35
|
}
|
|
34
36
|
/**
|
|
35
37
|
* Removes a previously registered event listener.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-emitter.js","names":["#listeners"],"sources":["../../src/utils/event-emitter.ts"],"sourcesContent":["type EventCallback<T = unknown> = (data: T) => void;\n\n/**\n * Minimal typed event emitter used by SDK services to publish auth and lifecycle state changes.\n */\nexport class EventEmitter<TEvents extends { [K in keyof TEvents]: unknown }> {\n #listeners: Map<keyof TEvents, Set<EventCallback>> = new Map();\n\n /**\n * Registers an event listener and returns an unsubscribe function.\n */\n on<K extends keyof TEvents>(event: K, callback: EventCallback<TEvents[K]>): () => void {\n if (!this.#listeners.has(event)) {\n this.#listeners.set(event, new Set());\n }\n this.#listeners.get(event)!.add(callback as EventCallback);\n\n return () => {\n this.#listeners.get(event)?.delete(callback as EventCallback);\n };\n }\n\n /**\n * Registers an event listener that runs at most once.\n */\n once<K extends keyof TEvents>(event: K, callback: EventCallback<TEvents[K]>): () => void {\n const unsubscribe = this.on(event, (data) => {\n unsubscribe();\n callback(data);\n });\n return unsubscribe;\n }\n\n /**\n * Emits an event to all registered listeners.\n */\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void {\n const callbacks = this.#listeners.get(event);\n if (callbacks) {\n for (const callback of callbacks) {\n callback(data);\n }\n }\n }\n\n /**\n * Removes a previously registered event listener.\n */\n off<K extends keyof TEvents>(event: K, callback?: EventCallback<TEvents[K]>): void {\n if (callback) {\n this.#listeners.get(event)?.delete(callback as EventCallback);\n } else {\n this.#listeners.delete(event);\n }\n }\n\n /**\n * Removes every registered event listener.\n */\n removeAllListeners(): void {\n this.#listeners.clear();\n }\n}\n"],"mappings":";;;;AAKA,IAAa,eAAb,MAA6E;CACzE,6BAAqD,IAAI,IAAI;;;;CAK7D,GAA4B,OAAU,UAAiD;EACnF,IAAI,CAAC,KAAKA,WAAW,IAAI,KAAK,GAC1B,KAAKA,WAAW,IAAI,uBAAO,IAAI,IAAI,CAAC;EAExC,KAAKA,WAAW,IAAI,KAAK,CAAC,CAAE,IAAI,QAAyB;EAEzD,aAAa;GACT,KAAKA,WAAW,IAAI,KAAK,CAAC,EAAE,OAAO,QAAyB;EAChE;CACJ;;;;CAKA,KAA8B,OAAU,UAAiD;EACrF,MAAM,cAAc,KAAK,GAAG,QAAQ,SAAS;GACzC,YAAY;GACZ,SAAS,IAAI;EACjB,CAAC;EACD,OAAO;CACX;;;;CAKA,KAA8B,OAAU,MAAwB;EAC5D,MAAM,YAAY,KAAKA,WAAW,IAAI,KAAK;EAC3C,IAAI,WACA,KAAK,MAAM,YAAY,WACnB,SAAS,IAAI;
|
|
1
|
+
{"version":3,"file":"event-emitter.js","names":["#listeners"],"sources":["../../src/utils/event-emitter.ts"],"sourcesContent":["type EventCallback<T = unknown> = (data: T) => void;\n\n/**\n * Minimal typed event emitter used by SDK services to publish auth and lifecycle state changes.\n */\nexport class EventEmitter<TEvents extends { [K in keyof TEvents]: unknown }> {\n #listeners: Map<keyof TEvents, Set<EventCallback>> = new Map();\n\n /**\n * Registers an event listener and returns an unsubscribe function.\n */\n on<K extends keyof TEvents>(event: K, callback: EventCallback<TEvents[K]>): () => void {\n if (!this.#listeners.has(event)) {\n this.#listeners.set(event, new Set());\n }\n this.#listeners.get(event)!.add(callback as EventCallback);\n\n return () => {\n this.#listeners.get(event)?.delete(callback as EventCallback);\n };\n }\n\n /**\n * Registers an event listener that runs at most once.\n */\n once<K extends keyof TEvents>(event: K, callback: EventCallback<TEvents[K]>): () => void {\n const unsubscribe = this.on(event, (data) => {\n unsubscribe();\n callback(data);\n });\n return unsubscribe;\n }\n\n /**\n * Emits an event to all registered listeners, isolating errors thrown synchronously by each listener.\n */\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void {\n const callbacks = this.#listeners.get(event);\n if (callbacks) {\n for (const callback of callbacks) {\n try {\n callback(data);\n } catch {\n // A consumer callback must not interrupt the SDK operation or other listeners.\n }\n }\n }\n }\n\n /**\n * Removes a previously registered event listener.\n */\n off<K extends keyof TEvents>(event: K, callback?: EventCallback<TEvents[K]>): void {\n if (callback) {\n this.#listeners.get(event)?.delete(callback as EventCallback);\n } else {\n this.#listeners.delete(event);\n }\n }\n\n /**\n * Removes every registered event listener.\n */\n removeAllListeners(): void {\n this.#listeners.clear();\n }\n}\n"],"mappings":";;;;AAKA,IAAa,eAAb,MAA6E;CACzE,6BAAqD,IAAI,IAAI;;;;CAK7D,GAA4B,OAAU,UAAiD;EACnF,IAAI,CAAC,KAAKA,WAAW,IAAI,KAAK,GAC1B,KAAKA,WAAW,IAAI,uBAAO,IAAI,IAAI,CAAC;EAExC,KAAKA,WAAW,IAAI,KAAK,CAAC,CAAE,IAAI,QAAyB;EAEzD,aAAa;GACT,KAAKA,WAAW,IAAI,KAAK,CAAC,EAAE,OAAO,QAAyB;EAChE;CACJ;;;;CAKA,KAA8B,OAAU,UAAiD;EACrF,MAAM,cAAc,KAAK,GAAG,QAAQ,SAAS;GACzC,YAAY;GACZ,SAAS,IAAI;EACjB,CAAC;EACD,OAAO;CACX;;;;CAKA,KAA8B,OAAU,MAAwB;EAC5D,MAAM,YAAY,KAAKA,WAAW,IAAI,KAAK;EAC3C,IAAI,WACA,KAAK,MAAM,YAAY,WACnB,IAAI;GACA,SAAS,IAAI;EACjB,QAAQ,CAER;CAGZ;;;;CAKA,IAA6B,OAAU,UAA4C;EAC/E,IAAI,UACA,KAAKA,WAAW,IAAI,KAAK,CAAC,EAAE,OAAO,QAAyB;OAE5D,KAAKA,WAAW,OAAO,KAAK;CAEpC;;;;CAKA,qBAA2B;EACvB,KAAKA,WAAW,MAAM;CAC1B;AACJ"}
|
package/dist/utils/evm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ConfigurationError } from "../shared/errors.js";
|
|
2
|
-
import { bytesToHex, hexToBytes, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
3
2
|
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
3
|
+
import { bytesToHex, hexToBytes, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
4
4
|
//#region src/utils/evm.ts
|
|
5
5
|
const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
6
6
|
/** Format-only address check (viem `isAddress(value, { strict: false })`). */
|
|
@@ -44,7 +44,7 @@ function evmUtf8ToHex(value) {
|
|
|
44
44
|
}
|
|
45
45
|
/** 0x-prefixed hex to bytes (viem `hexToBytes`); throws on malformed input. */
|
|
46
46
|
function evmHexToBytes(value) {
|
|
47
|
-
if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(value)) throw new ConfigurationError(
|
|
47
|
+
if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(value)) throw new ConfigurationError("Invalid hex value");
|
|
48
48
|
return hexToBytes(value.slice(2).toLowerCase());
|
|
49
49
|
}
|
|
50
50
|
//#endregion
|
package/dist/utils/evm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evm.js","names":["nobleHexToBytes"],"sources":["../../src/utils/evm.ts"],"sourcesContent":["import { keccak_256 } from \"@noble/hashes/sha3.js\";\nimport { bytesToHex, hexToBytes as nobleHexToBytes, utf8ToBytes } from \"@noble/hashes/utils.js\";\nimport { ConfigurationError } from \"../shared/errors.js\";\n\n/**\n * Minimal EVM helpers backed by @noble/hashes.\n *\n * The SDK core previously imported these five utilities from viem. Rolldown\n * groups all shared viem modules into a single chunk, so those tiny static\n * imports forced viem's entire abi/actions graph (~270 KB emitted) into the\n * app shell and the server's eager exec path, even though everything heavy is\n * loaded lazily. Semantics mirror the viem calls they replaced:\n * `isAddress(x, { strict: false })`, `getAddress`, `keccak256`,\n * `stringToBytes`, `hexToBytes`.\n */\n\nexport type EvmHex = `0x${string}`;\n\nconst ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\n\n/** Format-only address check (viem `isAddress(value, { strict: false })`). */\nexport function isEvmAddress(value: string): value is EvmHex {\n return ADDRESS_RE.test(value);\n}\n\n/**\n * viem `isAddress(value)` default-mode parity: format check plus EIP-55\n * checksum validation for any address that is not all-lowercase.\n */\nexport function isEvmAddressStrict(value: string): value is EvmHex {\n if (!isEvmAddress(value)) return false;\n const body = value.slice(2);\n // viem only exempts all-lowercase addresses from checksum validation.\n if (body === body.toLowerCase()) return true;\n return checksumEvmAddress(value) === value;\n}\n\n/** EIP-55 checksummed address (viem `getAddress`); throws on invalid input. */\nexport function checksumEvmAddress(value: string): EvmHex {\n if (!isEvmAddress(value)) {\n throw new ConfigurationError(`Invalid EVM address: ${value}`);\n }\n const lower = value.slice(2).toLowerCase();\n const hash = keccak_256(utf8ToBytes(lower));\n let out = \"0x\";\n for (let i = 0; i < 40; i++) {\n const char = lower[i]!;\n // Each hash byte covers two nibbles of the address.\n const nibble = (hash[i >> 1]! >> (i % 2 === 0 ? 4 : 0)) & 0x0f;\n out += nibble >= 8 ? char.toUpperCase() : char;\n }\n return out as EvmHex;\n}\n\n/** keccak-256 of raw bytes, hex-encoded (viem `keccak256(bytes)`). */\nexport function keccak256Hex(bytes: Uint8Array): EvmHex {\n return `0x${bytesToHex(keccak_256(bytes))}`;\n}\n\n/** UTF-8 encode (viem `stringToBytes`). */\nexport function evmUtf8ToBytes(value: string): Uint8Array {\n return utf8ToBytes(value);\n}\n\n/** UTF-8 string to 0x-prefixed hex (viem `stringToHex`). */\nexport function evmUtf8ToHex(value: string): EvmHex {\n return `0x${bytesToHex(utf8ToBytes(value))}`;\n}\n\n/** 0x-prefixed hex to bytes (viem `hexToBytes`); throws on malformed input. */\nexport function evmHexToBytes(value: string): Uint8Array {\n if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(value)) {\n throw new ConfigurationError(
|
|
1
|
+
{"version":3,"file":"evm.js","names":["nobleHexToBytes"],"sources":["../../src/utils/evm.ts"],"sourcesContent":["import { keccak_256 } from \"@noble/hashes/sha3.js\";\nimport { bytesToHex, hexToBytes as nobleHexToBytes, utf8ToBytes } from \"@noble/hashes/utils.js\";\nimport { ConfigurationError } from \"../shared/errors.js\";\n\n/**\n * Minimal EVM helpers backed by @noble/hashes.\n *\n * The SDK core previously imported these five utilities from viem. Rolldown\n * groups all shared viem modules into a single chunk, so those tiny static\n * imports forced viem's entire abi/actions graph (~270 KB emitted) into the\n * app shell and the server's eager exec path, even though everything heavy is\n * loaded lazily. Semantics mirror the viem calls they replaced:\n * `isAddress(x, { strict: false })`, `getAddress`, `keccak256`,\n * `stringToBytes`, `hexToBytes`.\n */\n\nexport type EvmHex = `0x${string}`;\n\nconst ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\n\n/** Format-only address check (viem `isAddress(value, { strict: false })`). */\nexport function isEvmAddress(value: string): value is EvmHex {\n return ADDRESS_RE.test(value);\n}\n\n/**\n * viem `isAddress(value)` default-mode parity: format check plus EIP-55\n * checksum validation for any address that is not all-lowercase.\n */\nexport function isEvmAddressStrict(value: string): value is EvmHex {\n if (!isEvmAddress(value)) return false;\n const body = value.slice(2);\n // viem only exempts all-lowercase addresses from checksum validation.\n if (body === body.toLowerCase()) return true;\n return checksumEvmAddress(value) === value;\n}\n\n/** EIP-55 checksummed address (viem `getAddress`); throws on invalid input. */\nexport function checksumEvmAddress(value: string): EvmHex {\n if (!isEvmAddress(value)) {\n throw new ConfigurationError(`Invalid EVM address: ${value}`);\n }\n const lower = value.slice(2).toLowerCase();\n const hash = keccak_256(utf8ToBytes(lower));\n let out = \"0x\";\n for (let i = 0; i < 40; i++) {\n const char = lower[i]!;\n // Each hash byte covers two nibbles of the address.\n const nibble = (hash[i >> 1]! >> (i % 2 === 0 ? 4 : 0)) & 0x0f;\n out += nibble >= 8 ? char.toUpperCase() : char;\n }\n return out as EvmHex;\n}\n\n/** keccak-256 of raw bytes, hex-encoded (viem `keccak256(bytes)`). */\nexport function keccak256Hex(bytes: Uint8Array): EvmHex {\n return `0x${bytesToHex(keccak_256(bytes))}`;\n}\n\n/** UTF-8 encode (viem `stringToBytes`). */\nexport function evmUtf8ToBytes(value: string): Uint8Array {\n return utf8ToBytes(value);\n}\n\n/** UTF-8 string to 0x-prefixed hex (viem `stringToHex`). */\nexport function evmUtf8ToHex(value: string): EvmHex {\n return `0x${bytesToHex(utf8ToBytes(value))}`;\n}\n\n/** 0x-prefixed hex to bytes (viem `hexToBytes`); throws on malformed input. */\nexport function evmHexToBytes(value: string): Uint8Array {\n if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(value)) {\n throw new ConfigurationError(\"Invalid hex value\");\n }\n return nobleHexToBytes(value.slice(2).toLowerCase());\n}\n"],"mappings":";;;;AAkBA,MAAM,aAAa;;AAGnB,SAAgB,aAAa,OAAgC;CACzD,OAAO,WAAW,KAAK,KAAK;AAChC;;;;;AAMA,SAAgB,mBAAmB,OAAgC;CAC/D,IAAI,CAAC,aAAa,KAAK,GAAG,OAAO;CACjC,MAAM,OAAO,MAAM,MAAM,CAAC;CAE1B,IAAI,SAAS,KAAK,YAAY,GAAG,OAAO;CACxC,OAAO,mBAAmB,KAAK,MAAM;AACzC;;AAGA,SAAgB,mBAAmB,OAAuB;CACtD,IAAI,CAAC,aAAa,KAAK,GACnB,MAAM,IAAI,mBAAmB,wBAAwB,OAAO;CAEhE,MAAM,QAAQ,MAAM,MAAM,CAAC,CAAC,CAAC,YAAY;CACzC,MAAM,OAAO,WAAW,YAAY,KAAK,CAAC;CAC1C,IAAI,MAAM;CACV,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EACzB,MAAM,OAAO,MAAM;EAEnB,MAAM,SAAU,KAAK,KAAK,OAAQ,IAAI,MAAM,IAAI,IAAI,KAAM;EAC1D,OAAO,UAAU,IAAI,KAAK,YAAY,IAAI;CAC9C;CACA,OAAO;AACX;;AAGA,SAAgB,aAAa,OAA2B;CACpD,OAAO,KAAK,WAAW,WAAW,KAAK,CAAC;AAC5C;;AAGA,SAAgB,eAAe,OAA2B;CACtD,OAAO,YAAY,KAAK;AAC5B;;AAGA,SAAgB,aAAa,OAAuB;CAChD,OAAO,KAAK,WAAW,YAAY,KAAK,CAAC;AAC7C;;AAGA,SAAgB,cAAc,OAA2B;CACrD,IAAI,CAAC,0BAA0B,KAAK,KAAK,GACrC,MAAM,IAAI,mBAAmB,mBAAmB;CAEpD,OAAOA,WAAgB,MAAM,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;AACvD"}
|
package/dist/utils/jwt.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
//#region src/utils/jwt.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Checks whether a
|
|
3
|
+
* Checks whether a value is a present, well-formed, unexpired JWT string.
|
|
4
4
|
*/
|
|
5
|
-
declare function isJwtValid(token:
|
|
5
|
+
declare function isJwtValid(token: unknown): token is string;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { isJwtValid };
|
|
8
8
|
//# sourceMappingURL=jwt.d.ts.map
|
package/dist/utils/jwt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.d.ts","names":[],"sources":["../../src/utils/jwt.ts"],"mappings":";;;;iBA6DgB,WAAW,
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","names":[],"sources":["../../src/utils/jwt.ts"],"mappings":";;;;iBA6DgB,WAAW,iBAAiB"}
|
package/dist/utils/jwt.js
CHANGED
|
@@ -49,10 +49,10 @@ function isJwtExpired(token) {
|
|
|
49
49
|
return exp < Math.floor(Date.now() / 1e3);
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
|
-
* Checks whether a
|
|
52
|
+
* Checks whether a value is a present, well-formed, unexpired JWT string.
|
|
53
53
|
*/
|
|
54
54
|
function isJwtValid(token) {
|
|
55
|
-
if (!token) return false;
|
|
55
|
+
if (typeof token !== "string" || !token) return false;
|
|
56
56
|
if (!isJwt(token)) return false;
|
|
57
57
|
if (isJwtExpired(token)) return false;
|
|
58
58
|
return true;
|
package/dist/utils/jwt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.js","names":[],"sources":["../../src/utils/jwt.ts"],"sourcesContent":["/**\n * Checks whether a string has the shape of a JWT.\n */\nexport function isJwt(token: string): boolean {\n const parts = token.split(\".\");\n return parts.length === 3 && !!parts[0] && !!parts[1] && !!parts[2];\n}\n\nlet textDecoder: TextDecoder | undefined;\n\n/**\n * Gets a TextDecoder instance.\n */\nfunction getTextDecoder(): TextDecoder {\n textDecoder ??= new TextDecoder(\"utf-8\", { fatal: true });\n return textDecoder;\n}\n\nfunction decodeBase64Url(value: string): string | null {\n const remainder = value.length % 4;\n if (remainder === 1) return null;\n\n const base64 = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const paddedBase64 =\n remainder === 0 ? base64 : base64.padEnd(base64.length + 4 - remainder, \"=\");\n const binary = atob(paddedBase64);\n const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));\n return getTextDecoder().decode(bytes);\n}\n\n/**\n * Reads a JWT expiration timestamp when present.\n */\nexport function getJwtExpiration(token: string): number | null {\n try {\n const [_, rawPayload] = token.split(\".\");\n if (!rawPayload) return null;\n const decodedPayload = decodeBase64Url(rawPayload);\n if (!decodedPayload) return null;\n const payload: unknown = JSON.parse(decodedPayload);\n if (typeof payload !== \"object\" || payload === null) return null;\n const exp = (payload as { exp?: unknown }).exp;\n return typeof exp === \"number\" ? exp : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Checks whether a JWT is expired.\n */\nexport function isJwtExpired(token: string): boolean {\n const exp = getJwtExpiration(token);\n if (exp === null) return true;\n const currentTime = Math.floor(Date.now() / 1000);\n return exp < currentTime;\n}\n\n/**\n * Checks whether a
|
|
1
|
+
{"version":3,"file":"jwt.js","names":[],"sources":["../../src/utils/jwt.ts"],"sourcesContent":["/**\n * Checks whether a string has the shape of a JWT.\n */\nexport function isJwt(token: string): boolean {\n const parts = token.split(\".\");\n return parts.length === 3 && !!parts[0] && !!parts[1] && !!parts[2];\n}\n\nlet textDecoder: TextDecoder | undefined;\n\n/**\n * Gets a TextDecoder instance.\n */\nfunction getTextDecoder(): TextDecoder {\n textDecoder ??= new TextDecoder(\"utf-8\", { fatal: true });\n return textDecoder;\n}\n\nfunction decodeBase64Url(value: string): string | null {\n const remainder = value.length % 4;\n if (remainder === 1) return null;\n\n const base64 = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const paddedBase64 =\n remainder === 0 ? base64 : base64.padEnd(base64.length + 4 - remainder, \"=\");\n const binary = atob(paddedBase64);\n const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));\n return getTextDecoder().decode(bytes);\n}\n\n/**\n * Reads a JWT expiration timestamp when present.\n */\nexport function getJwtExpiration(token: string): number | null {\n try {\n const [_, rawPayload] = token.split(\".\");\n if (!rawPayload) return null;\n const decodedPayload = decodeBase64Url(rawPayload);\n if (!decodedPayload) return null;\n const payload: unknown = JSON.parse(decodedPayload);\n if (typeof payload !== \"object\" || payload === null) return null;\n const exp = (payload as { exp?: unknown }).exp;\n return typeof exp === \"number\" ? exp : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Checks whether a JWT is expired.\n */\nexport function isJwtExpired(token: string): boolean {\n const exp = getJwtExpiration(token);\n if (exp === null) return true;\n const currentTime = Math.floor(Date.now() / 1000);\n return exp < currentTime;\n}\n\n/**\n * Checks whether a value is a present, well-formed, unexpired JWT string.\n */\nexport function isJwtValid(token: unknown): token is string {\n if (typeof token !== \"string\" || !token) return false;\n if (!isJwt(token)) return false;\n if (isJwtExpired(token)) return false;\n return true;\n}\n\n/**\n * Returns the number of milliseconds until the JWT expires.\n * Returns 0 if already expired or invalid.\n */\nexport function getJwtTimeToExpiry(token: string): number {\n const exp = getJwtExpiration(token);\n if (exp === null) return 0;\n const nowMs = Date.now();\n const expiresAtMs = exp * 1000;\n return Math.max(0, expiresAtMs - nowMs);\n}\n"],"mappings":";;;;AAGA,SAAgB,MAAM,OAAwB;CAC1C,MAAM,QAAQ,MAAM,MAAM,GAAG;CAC7B,OAAO,MAAM,WAAW,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,MAAM;AACrE;AAEA,IAAI;;;;AAKJ,SAAS,iBAA8B;CACnC,gBAAgB,IAAI,YAAY,SAAS,EAAE,OAAO,KAAK,CAAC;CACxD,OAAO;AACX;AAEA,SAAS,gBAAgB,OAA8B;CACnD,MAAM,YAAY,MAAM,SAAS;CACjC,IAAI,cAAc,GAAG,OAAO;CAE5B,MAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,CAAC,CAAC,QAAQ,MAAM,GAAG;CACzD,MAAM,eACF,cAAc,IAAI,SAAS,OAAO,OAAO,OAAO,SAAS,IAAI,WAAW,GAAG;CAC/E,MAAM,SAAS,KAAK,YAAY;CAChC,MAAM,QAAQ,WAAW,KAAK,SAAS,cAAc,UAAU,WAAW,CAAC,CAAC;CAC5E,OAAO,eAAe,CAAC,CAAC,OAAO,KAAK;AACxC;;;;AAKA,SAAgB,iBAAiB,OAA8B;CAC3D,IAAI;EACA,MAAM,CAAC,GAAG,cAAc,MAAM,MAAM,GAAG;EACvC,IAAI,CAAC,YAAY,OAAO;EACxB,MAAM,iBAAiB,gBAAgB,UAAU;EACjD,IAAI,CAAC,gBAAgB,OAAO;EAC5B,MAAM,UAAmB,KAAK,MAAM,cAAc;EAClD,IAAI,OAAO,YAAY,YAAY,YAAY,MAAM,OAAO;EAC5D,MAAM,MAAO,QAA8B;EAC3C,OAAO,OAAO,QAAQ,WAAW,MAAM;CAC3C,QAAQ;EACJ,OAAO;CACX;AACJ;;;;AAKA,SAAgB,aAAa,OAAwB;CACjD,MAAM,MAAM,iBAAiB,KAAK;CAClC,IAAI,QAAQ,MAAM,OAAO;CAEzB,OAAO,MADa,KAAK,MAAM,KAAK,IAAI,IAAI,GACrB;AAC3B;;;;AAKA,SAAgB,WAAW,OAAiC;CACxD,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,OAAO;CAChD,IAAI,CAAC,MAAM,KAAK,GAAG,OAAO;CAC1B,IAAI,aAAa,KAAK,GAAG,OAAO;CAChC,OAAO;AACX;;;;;AAMA,SAAgB,mBAAmB,OAAuB;CACtD,MAAM,MAAM,iBAAiB,KAAK;CAClC,IAAI,QAAQ,MAAM,OAAO;CACzB,MAAM,QAAQ,KAAK,IAAI;CACvB,MAAM,cAAc,MAAM;CAC1B,OAAO,KAAK,IAAI,GAAG,cAAc,KAAK;AAC1C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polyester/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "TypeScript SDK providing access to APIs on Polyester Exchange.",
|
|
6
6
|
"homepage": "https://github.com/Fabric-Labs/polyester-sdk-typescript#readme",
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
"changeset": "changeset",
|
|
90
90
|
"version-packages": "changeset version && bun install --lockfile-only",
|
|
91
91
|
"release": "changeset publish",
|
|
92
|
-
"verify:package": "bun scripts/verify-package-exports.ts",
|
|
93
|
-
"ci": "bun run lint && bun run format:check && bun run check && bun run test && bun run
|
|
92
|
+
"verify:package": "bun run build && bun scripts/verify-package-exports.ts",
|
|
93
|
+
"ci": "bun run lint && bun run format:check && bun run check && bun run test && bun run verify:package"
|
|
94
94
|
},
|
|
95
95
|
"dependencies": {
|
|
96
96
|
"@bufbuild/protobuf": "2.13.0",
|