@andco/sdk-svelte 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +46 -23
- package/dist/AndCoButton.svelte +24 -18
- package/dist/AndCoButton.svelte.d.ts +1 -1
- package/dist/context.svelte.d.ts +29 -0
- package/dist/context.svelte.js +38 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +12 -2
package/LICENSE
CHANGED
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
same "printed page" as the copyright notice for easier
|
|
188
188
|
identification within third-party archives.
|
|
189
189
|
|
|
190
|
-
Copyright 2026
|
|
190
|
+
Copyright 2026 Haulmer
|
|
191
191
|
|
|
192
192
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
193
|
you may not use this file except in compliance with the License.
|
package/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# `@andco/sdk-svelte`
|
|
2
2
|
|
|
3
|
+
> [!WARNING]
|
|
4
|
+
> **Pre-1.0 software.** Until version 1.0.0 is released, any new version may include breaking
|
|
5
|
+
> changes, including minor and patch releases. Expect any API incompatibility and data resets
|
|
6
|
+
> in the Andco environments without prior notice. Pin an exact version and review the release
|
|
7
|
+
> notes before upgrading.
|
|
8
|
+
|
|
3
9
|
Svelte 5 bindings for `@andco/sdk`, implemented with runes, callback props,
|
|
4
10
|
and Svelte context.
|
|
5
11
|
|
|
@@ -22,10 +28,11 @@ that wants to hand the provider a session resolved ahead of time via `initialSes
|
|
|
22
28
|
```svelte
|
|
23
29
|
<script lang="ts">
|
|
24
30
|
import { AndcoProvider } from "@andco/sdk-svelte";
|
|
31
|
+
import type { AndcoBrowserOptions } from "@andco/sdk/browser";
|
|
25
32
|
|
|
26
33
|
import App from "./App.svelte";
|
|
27
34
|
|
|
28
|
-
const clientOptions = {
|
|
35
|
+
const clientOptions: AndcoBrowserOptions = {
|
|
29
36
|
clientId: "client_123",
|
|
30
37
|
endpointAuth: "https://auth.example.com",
|
|
31
38
|
endpointApi: "https://api.example.com",
|
|
@@ -52,7 +59,7 @@ them.
|
|
|
52
59
|
Svelte 5 callback props use lowercase DOM-style names. `AndcoButton` takes its client, endpoints,
|
|
53
60
|
and theme from the `<AndcoProvider>` context, not from props — the only thing a per-render sign-in
|
|
54
61
|
needs to pass is `authorization`, the same request-local options `auth.signIn` accepts (`scopes`,
|
|
55
|
-
`redirectTo`, `
|
|
62
|
+
`redirectTo`, `authorizations`, `authorizationDetails`, `resource`, …):
|
|
56
63
|
|
|
57
64
|
```svelte
|
|
58
65
|
<script lang="ts">
|
|
@@ -105,18 +112,32 @@ expiry, or to observe the unresolved-to-anonymous transition `useAndco`
|
|
|
105
112
|
deliberately hides. `useAndcoUser().current` changes only when the person
|
|
106
113
|
changes — identifier, name, email, or avatar.
|
|
107
114
|
|
|
108
|
-
## Progressive
|
|
115
|
+
## Progressive permissions
|
|
116
|
+
|
|
117
|
+
Scopes are OpenID Connect only; resource permissions are RARs built by the Resource Server's
|
|
118
|
+
authorization builder:
|
|
109
119
|
|
|
110
120
|
```svelte
|
|
111
|
-
|
|
112
|
-
|
|
121
|
+
<script lang="ts">
|
|
122
|
+
import { Bank } from "@andco/bank-sdk";
|
|
123
|
+
import { AndcoButton, useAndcoSession } from "@andco/sdk-svelte";
|
|
124
|
+
|
|
125
|
+
const session = useAndcoSession();
|
|
126
|
+
const bank = new Bank();
|
|
127
|
+
const accounts = bank.accounts.authorization({ actions: ["read"], subject: { type: "profile" } });
|
|
128
|
+
</script>
|
|
129
|
+
|
|
130
|
+
{#if session.current}
|
|
131
|
+
<AndcoButton authorization={{ authorizations: [accounts] }} />
|
|
113
132
|
{/if}
|
|
114
133
|
```
|
|
115
134
|
|
|
116
135
|
## Intents
|
|
117
136
|
|
|
118
|
-
Deposit and
|
|
119
|
-
|
|
137
|
+
Deposit and transfer creation live on the Andco Bank Resource Server Definition, by domain
|
|
138
|
+
(`bank.deposits`, `bank.transfers`, `bank.accounts`), not on the core client's domain-neutral
|
|
139
|
+
`intents`. Build it from the signed-in identity's credentials — it takes the client id and endpoint
|
|
140
|
+
from them — then use it:
|
|
120
141
|
|
|
121
142
|
```svelte
|
|
122
143
|
<script lang="ts">
|
|
@@ -124,8 +145,7 @@ core client's domain-neutral `intents`. Bind it to the signed-in identity once,
|
|
|
124
145
|
import { Bank } from "@andco/bank-sdk";
|
|
125
146
|
|
|
126
147
|
const andco = useAndcoAuthed();
|
|
127
|
-
const
|
|
128
|
-
const bank = $derived(andco.current ? bankDefinition.use(andco.current) : null);
|
|
148
|
+
const bank = $derived(andco.current ? new Bank(andco.current) : null);
|
|
129
149
|
</script>
|
|
130
150
|
```
|
|
131
151
|
|
|
@@ -133,16 +153,17 @@ core client's domain-neutral `intents`. Bind it to the signed-in identity once,
|
|
|
133
153
|
<script lang="ts">
|
|
134
154
|
async function topUp() {
|
|
135
155
|
if (!bank) return;
|
|
136
|
-
const { data: deposit, error } = await bank.
|
|
156
|
+
const { data: deposit, error } = await bank.deposits.create(
|
|
137
157
|
{
|
|
138
158
|
expires_in: "30 minutes",
|
|
139
|
-
amount: { currency: "CLP",
|
|
140
|
-
note: {
|
|
159
|
+
amount: { currency: "CLP", value: "40000", editable: false },
|
|
160
|
+
note: { value: "Wallet top-up", editable: true },
|
|
141
161
|
metadata: { merchant_transaction_id: "deposit_8472" },
|
|
142
162
|
},
|
|
143
163
|
{ idempotencyKey: "deposit:8472" },
|
|
144
164
|
);
|
|
145
165
|
if (error) throw error;
|
|
166
|
+
andco.current?.intents.present(deposit, { presentation: "popup" });
|
|
146
167
|
}
|
|
147
168
|
</script>
|
|
148
169
|
|
|
@@ -151,19 +172,21 @@ core client's domain-neutral `intents`. Bind it to the signed-in identity once,
|
|
|
151
172
|
|
|
152
173
|
`AndcoIntentButton` renders the same hosted iframe as `AndcoButton`, with its `flow` fixed to
|
|
153
174
|
`"intent"` — the Hosted Intent Presentation is the canonical way a person confirms an Intent, and
|
|
154
|
-
its DOM and code stay Andco's, never the Project's. It takes the
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
state with `bank.intents.get(intentId)` after it fires, or through `bank.intents.getEvents(intentId)`
|
|
159
|
-
or the domain-specific listeners (`onIntentDepositEvent`, `onIntentWithdrawalEvent`), rather than
|
|
160
|
-
expecting it on the callback.
|
|
175
|
+
its DOM and code stay Andco's, never the Project's. It takes the props of `AndcoButton` plus a
|
|
176
|
+
required `intentId`: an id, or a function that resolves it *after* the person activates the control,
|
|
177
|
+
so the window is already open when the Intent is created. `oncomplete` receives
|
|
178
|
+
`{ outcome, intent }`; only `intent`, read after the interaction, says what happened to the money.
|
|
161
179
|
|
|
162
180
|
```svelte
|
|
163
|
-
<AndcoIntentButton
|
|
181
|
+
<AndcoIntentButton
|
|
182
|
+
intentId={async () => {
|
|
183
|
+
const response = await fetch("/api/create-transfer", { method: "POST" });
|
|
184
|
+
return (await response.json())["intent_id"];
|
|
185
|
+
}}
|
|
186
|
+
oncomplete={(result) => console.log(result.outcome, result.intent.status)}
|
|
187
|
+
onerror={(error) => console.error(error.message)}
|
|
188
|
+
/>
|
|
164
189
|
```
|
|
165
190
|
|
|
166
|
-
See [`apps/example-svelte`](
|
|
191
|
+
See [`apps/example-svelte`](https://github.com/haulmer/andco-sdk-js/tree/main/apps/example-svelte) for the complete
|
|
167
192
|
session → Grant → resource flow.
|
|
168
|
-
|
|
169
|
-
There is no separate hosted-vs-direct pair of Intent buttons — `AndcoIntentButton` is the only one.
|
package/dist/AndCoButton.svelte
CHANGED
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
type Options = AndcoButtonControllerOptions;
|
|
12
12
|
type Props = Omit<HTMLIframeAttributes, "onerror" | "referrerpolicy" | "sandbox" | "src" | "srcdoc"> &
|
|
13
|
-
Pick<
|
|
13
|
+
Pick<
|
|
14
|
+
Options,
|
|
15
|
+
"authorization" | "busy" | "disabled" | "flow" | "intentId" | "locale" | "presentation" | "release" | "themeMode"
|
|
16
|
+
> & {
|
|
14
17
|
onready?: Options["onReady"];
|
|
15
18
|
onactivate?: Options["onActivate"];
|
|
16
19
|
oncomplete?: Options["onComplete"];
|
|
@@ -25,6 +28,7 @@
|
|
|
25
28
|
flow,
|
|
26
29
|
intentId,
|
|
27
30
|
locale,
|
|
31
|
+
presentation,
|
|
28
32
|
release,
|
|
29
33
|
themeMode,
|
|
30
34
|
onready,
|
|
@@ -46,14 +50,15 @@
|
|
|
46
50
|
$effect(() => {
|
|
47
51
|
const next = new AndcoButtonController({
|
|
48
52
|
client,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
authorization,
|
|
54
|
+
flow,
|
|
55
|
+
intentId,
|
|
56
|
+
release,
|
|
57
|
+
themeMode,
|
|
58
|
+
locale,
|
|
59
|
+
presentation,
|
|
60
|
+
disabled,
|
|
61
|
+
busy,
|
|
57
62
|
onReady: (event) => onready?.(event),
|
|
58
63
|
onActivate: (event) => onactivate?.(event),
|
|
59
64
|
onComplete: (outcome) => oncomplete?.(outcome),
|
|
@@ -81,19 +86,20 @@
|
|
|
81
86
|
if (!iframe || !controller) return;
|
|
82
87
|
return controller.connect(iframe);
|
|
83
88
|
});
|
|
89
|
+
|
|
90
|
+
// The controller publishes the frame contract as data; this component only owns the element.
|
|
91
|
+
const defaultStyle = AndcoButtonController.frameStyleText(AndcoButtonController.IFRAME_DEFAULT_STYLE);
|
|
92
|
+
const frame = $derived(snapshot ? AndcoButtonController.frameProps(snapshot) : { src: undefined, hidden: true });
|
|
84
93
|
</script>
|
|
85
94
|
|
|
86
|
-
<!--
|
|
87
|
-
A bare iframe is 300x150 with a border, and the hosted control fills whatever box it is given, so
|
|
88
|
-
without a default the application sees a bordered grey slab. A `style` on the component wins.
|
|
89
|
-
-->
|
|
95
|
+
<!-- A `style` on the component wins over the default set here. -->
|
|
90
96
|
<iframe
|
|
91
|
-
style=
|
|
97
|
+
style={defaultStyle}
|
|
92
98
|
{...attributes}
|
|
93
99
|
bind:this={iframe}
|
|
94
|
-
hidden={
|
|
95
|
-
referrerpolicy=
|
|
96
|
-
sandbox=
|
|
97
|
-
src={
|
|
100
|
+
hidden={frame.hidden}
|
|
101
|
+
referrerpolicy={AndcoButtonController.IFRAME_REFERRER_POLICY}
|
|
102
|
+
sandbox={AndcoButtonController.IFRAME_SANDBOX}
|
|
103
|
+
src={frame.src}
|
|
98
104
|
{title}
|
|
99
105
|
></iframe>
|
|
@@ -2,7 +2,7 @@ import type { AndcoError } from "@andco/sdk";
|
|
|
2
2
|
import { type AndcoButtonControllerOptions } from "@andco/sdk/browser";
|
|
3
3
|
import type { HTMLIframeAttributes } from "svelte/elements";
|
|
4
4
|
type Options = AndcoButtonControllerOptions;
|
|
5
|
-
type Props = Omit<HTMLIframeAttributes, "onerror" | "referrerpolicy" | "sandbox" | "src" | "srcdoc"> & Pick<Options, "authorization" | "busy" | "disabled" | "flow" | "intentId" | "locale" | "release" | "themeMode"> & {
|
|
5
|
+
type Props = Omit<HTMLIframeAttributes, "onerror" | "referrerpolicy" | "sandbox" | "src" | "srcdoc"> & Pick<Options, "authorization" | "busy" | "disabled" | "flow" | "intentId" | "locale" | "presentation" | "release" | "themeMode"> & {
|
|
6
6
|
onready?: Options["onReady"];
|
|
7
7
|
onactivate?: Options["onActivate"];
|
|
8
8
|
oncomplete?: Options["onComplete"];
|
package/dist/context.svelte.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type AndcoClient, type AndcoClientAuthed, type AndcoSession, type AndcoUser } from "@andco/sdk";
|
|
2
|
+
/** Stable provider client and a reactive getter for the current session. */
|
|
2
3
|
export type AndcoSvelteContext = {
|
|
3
4
|
/** The instance. One reference for the provider's lifetime — never `with(...)` or `authorized()`. */
|
|
4
5
|
readonly client: AndcoClient;
|
|
5
6
|
readonly session: AndcoSession | null | undefined;
|
|
6
7
|
};
|
|
8
|
+
/** Registers the provider context during component initialization. */
|
|
7
9
|
export declare function setAndcoContext(context: AndcoSvelteContext): void;
|
|
8
10
|
/**
|
|
9
11
|
* The raw context: the stable instance plus the raw session.
|
|
@@ -72,6 +74,33 @@ export declare function useAndcoAuthed(): {
|
|
|
72
74
|
export declare function useAndcoSession(): {
|
|
73
75
|
readonly current: AndcoSession | null | undefined;
|
|
74
76
|
};
|
|
77
|
+
/**
|
|
78
|
+
* Instance Readiness: whether the store has finished its initial load.
|
|
79
|
+
*
|
|
80
|
+
* `false` until the load settles, then `true` for good. Not the same as being signed out — an
|
|
81
|
+
* instance that is not ready has not yet determined whether a session exists at all, which is
|
|
82
|
+
* exactly the `undefined` case {@link useAndcoSession} distinguishes from `null`. This rune is that
|
|
83
|
+
* same distinction read as a boolean, for the common case of gating a render on it rather than
|
|
84
|
+
* checking `undefined` directly.
|
|
85
|
+
*
|
|
86
|
+
* The load itself is already started by the provider's own subscription (`AndCoProvider.svelte`
|
|
87
|
+
* subscribes in its own `$effect`, before this rune ever runs), so reading this starts nothing new.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```svelte
|
|
91
|
+
* const ready = useAndcoReady();
|
|
92
|
+
* ```
|
|
93
|
+
* ```svelte
|
|
94
|
+
* {#if !ready.current}
|
|
95
|
+
* <Skeleton />
|
|
96
|
+
* {:else}
|
|
97
|
+
* {@render children()}
|
|
98
|
+
* {/if}
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export declare function useAndcoReady(): {
|
|
102
|
+
readonly current: boolean;
|
|
103
|
+
};
|
|
75
104
|
/**
|
|
76
105
|
* The authenticated person, or `null`/`undefined` sharing {@link useAndcoSession}'s three states.
|
|
77
106
|
*
|
package/dist/context.svelte.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { sessionIdentityKey, } from "@andco/sdk";
|
|
2
2
|
import { createContext } from "svelte";
|
|
3
3
|
const [get, set] = createContext();
|
|
4
|
+
/** Registers the provider context during component initialization. */
|
|
4
5
|
export function setAndcoContext(context) {
|
|
5
6
|
set(context);
|
|
6
7
|
}
|
|
@@ -102,6 +103,39 @@ export function useAndcoSession() {
|
|
|
102
103
|
},
|
|
103
104
|
};
|
|
104
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Instance Readiness: whether the store has finished its initial load.
|
|
108
|
+
*
|
|
109
|
+
* `false` until the load settles, then `true` for good. Not the same as being signed out — an
|
|
110
|
+
* instance that is not ready has not yet determined whether a session exists at all, which is
|
|
111
|
+
* exactly the `undefined` case {@link useAndcoSession} distinguishes from `null`. This rune is that
|
|
112
|
+
* same distinction read as a boolean, for the common case of gating a render on it rather than
|
|
113
|
+
* checking `undefined` directly.
|
|
114
|
+
*
|
|
115
|
+
* The load itself is already started by the provider's own subscription (`AndCoProvider.svelte`
|
|
116
|
+
* subscribes in its own `$effect`, before this rune ever runs), so reading this starts nothing new.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```svelte
|
|
120
|
+
* const ready = useAndcoReady();
|
|
121
|
+
* ```
|
|
122
|
+
* ```svelte
|
|
123
|
+
* {#if !ready.current}
|
|
124
|
+
* <Skeleton />
|
|
125
|
+
* {:else}
|
|
126
|
+
* {@render children()}
|
|
127
|
+
* {/if}
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export function useAndcoReady() {
|
|
131
|
+
const value = andcoContext();
|
|
132
|
+
const ready = $derived(value.session !== undefined);
|
|
133
|
+
return {
|
|
134
|
+
get current() {
|
|
135
|
+
return ready;
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
105
139
|
/**
|
|
106
140
|
* The authenticated person, or `null`/`undefined` sharing {@link useAndcoSession}'s three states.
|
|
107
141
|
*
|
|
@@ -130,7 +164,10 @@ export function useAndcoUser() {
|
|
|
130
164
|
cached.id !== next.id ||
|
|
131
165
|
cached.name !== next.name ||
|
|
132
166
|
cached.email !== next.email ||
|
|
133
|
-
cached.avatarUrl !== next.avatarUrl
|
|
167
|
+
cached.avatarUrl !== next.avatarUrl ||
|
|
168
|
+
cached.emailVerified !== next.emailVerified ||
|
|
169
|
+
cached.phone !== next.phone ||
|
|
170
|
+
cached.phoneVerified !== next.phoneVerified) {
|
|
134
171
|
cached = next;
|
|
135
172
|
}
|
|
136
173
|
return cached;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default as AndcoButton } from "./AndCoButton.svelte";
|
|
2
2
|
export { default as AndcoIntentButton } from "./AndCoIntentButton.svelte";
|
|
3
3
|
export { default as AndcoProvider } from "./AndCoProvider.svelte";
|
|
4
|
-
export { type AndcoSvelteContext, setAndcoContext, useAndco, useAndcoAuthed, useAndcoSession, useAndcoUser, } from "./context.svelte.js";
|
|
4
|
+
export { type AndcoSvelteContext, setAndcoContext, useAndco, useAndcoAuthed, useAndcoReady, useAndcoSession, useAndcoUser, } from "./context.svelte.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default as AndcoButton } from "./AndCoButton.svelte";
|
|
2
2
|
export { default as AndcoIntentButton } from "./AndCoIntentButton.svelte";
|
|
3
3
|
export { default as AndcoProvider } from "./AndCoProvider.svelte";
|
|
4
|
-
export { setAndcoContext, useAndco, useAndcoAuthed, useAndcoSession, useAndcoUser, } from "./context.svelte.js";
|
|
4
|
+
export { setAndcoContext, useAndco, useAndcoAuthed, useAndcoReady, useAndcoSession, useAndcoUser, } from "./context.svelte.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andco/sdk-svelte",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"svelte": "^5.0.0"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@andco/sdk": "0.0.
|
|
26
|
+
"@andco/sdk": "0.0.5"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@sveltejs/package": "^2.0.0",
|
|
@@ -36,6 +36,16 @@
|
|
|
36
36
|
},
|
|
37
37
|
"license": "Apache-2.0",
|
|
38
38
|
"description": "Svelte bindings for the Andco SDK.",
|
|
39
|
+
"author": "Patricio Lopez Juri <patricio.lopez@haulmer.com>",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/haulmer/andco-sdk-js.git",
|
|
43
|
+
"directory": "packages/sdk-svelte"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/haulmer/andco-sdk-js#readme",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/haulmer/andco-sdk-js/issues"
|
|
48
|
+
},
|
|
39
49
|
"scripts": {
|
|
40
50
|
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
41
51
|
"build": "pnpm run clean && svelte-package",
|